Создание нового родителя и дочернего элемента на одной странице
В моем приложении MVC есть классические отношения родитель-потомок (master-detail).
Я хочу иметь одну страницу, которая создаст как родителя, так и детей на одной странице. Я добавил действие, которое возвращает частичное представление, которое добавляет дочерний HTML в представление родителей, но я не знаю, как связать вновь созданный ребенок в действии с исходным родителем (другими словами, как добавить новый дочернего объекта для сбора этих объектов в родительском объекте).
Я предполагаю, что при отправке формы действие должно получить родительский объект с вновь созданными дочерними элементами в его коллекции.
Итак, чтобы сделать что-то не так, каков должен быть код действия, создающего дочерний объект и как дочерний элемент добавляется в его родительскую коллекцию?
Я прочитал много сообщений здесь (и других сайтов) и не смог найти пример.
В приложении используются MVC 4 и Entity Framework 5.
Пример кода (я удалил часть кода, чтобы она была простой).
Модель представляет собой формы (родительские) и объекты FormField (дочерние).
public partial class Form
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<FormField> FormFields { get; set; }
}
public partial class FormField
{
public int ID { get; set; }
public string Name { get; set; }
public int FormID { get; set; }
}
Следующий частичный вид (_CreateFormField.cshtml) создает новый FormField (дочерний элемент).
@model FormField
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>FormField</legend>
<div class="editor-label">
@Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Name)
@Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.FormID)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.FormID)
@Html.ValidationMessageFor(model => model.FormID)
</div>
</fieldset>
}
И следующий вид (Create.cshtml) - это тот, который создает форму.
@model Form
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>Form</legend>
<div class="editor-label">
@Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Name)
@Html.ValidationMessageFor(model => model.Name)
</div>
<div>
@Html.ActionLink(
"Add Field",
"CreateFormField",
new { id = -1},
new { @class = "form-field" })
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
<div id="CreateFormField"></div>
@section Scripts {
<script>
$(function () {
$('.form-field').on('click', function (e) {
$.get($(this).prop('href'), function (response) {
$('#CreateFormField').append(response)
});
e.preventDefault();
});
});
</script>
@Scripts.Render("~/bundles/jqueryval")
}
Следующие действия обрабатывают создание в FormController.
[HttpPost]
public ActionResult Create(Form form)
{
if (ModelState.IsValid)
{
db.Forms.Add(form);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(form);
}
public ActionResult CreateFormField(string id = null)
{
// I guess something is missing here.
return PartialView("_CreateFormField", new FormField());
}
Спасибо заранее,
Sharon.
Ответы
Ответ 1
Я думаю, что лучший и самый простой способ для вас - это то, что у вас есть представление о создании Form
, а внизу оно помещает fieldset
для назначения FormFields
ему.
Для набора полей у вас должно быть два частичных вида: один для создания и другой для редактирования. Частичное представление для создания должно быть примерно таким:
@model myPrj.Models.Form_FormFieldInfo
@{
var index = Guid.NewGuid().ToString();
string ln = (string)ViewBag.ListName;
string hn = ln + ".Index";
}
<tr>
<td>
<input type="hidden" name="@hn" value="@index" />
@Html.LabelFor(model => model.FormFieldID)
</td>
<td>
@Html.DropDownList(ln + "[" + index + "].FormFieldID",
new SelectList(new myPrj.Models.DbContext().FormFields, "ID", "FieldName"))
</td>
<td>
<input type="button" onclick="$(this).parent().parent().remove();"
value="Remove" />
</td>
</tr>
Вызывая это частичное представление в представлении create place ajaxly, вы можете отображать некоторые элементы для каждого тега. Каждая строка элементов содержит метку, теги DropDownList и кнопку удаления, чтобы просто удалить созданные элементы.
В представлении create place у вас есть голая таблица, которая будет содержать те элементы, которые вы создаете с помощью частичного представления:
<fieldset>
<legend>Form and FormFields</legend>
@Html.ValidationMessageFor(model => model.FormFields)</label>
<table id="tblFields"></table>
<input type="button" id="btnAddTag" value="Add new Field"/>
<img id="imgSpinnerl" src="~/Images/indicator-blue.gif" style="display:none;" />
</fieldset>
и у вас есть следующий script, чтобы создать строку элементов для каждого тега:
$(document).ready(function () {
$("#btnAddField").click(function () {
$.ajax({
url: "/Controller/GetFormFieldRow/FormFields",
type: 'GET', dataType: 'json',
success: function (data, textStatus, jqXHR) {
$("#tblFields").append(jqXHR.responseText);
},
error: function (jqXHR, textStatus, errorThrown) {
$("#tblFields").append(jqXHR.responseText);
},
beforeSend: function () { $("#imgSpinnerl").show(); },
complete: function () { $("#imgSpinnerl").hide(); }
});
});
});
Метод действия GetFormFieldRow
выглядит следующим образом:
public PartialViewResult GetFormFieldRow(string id = "")
{
ViewBag.ListName = id;
return PartialView("_FormFieldPartial");
}
и ваш результат для создания... Все решение для вашего вопроса имеет много кодов для просмотров, частичных представлений, контроллеров, аякс-вызовов и привязки к модели. Я пытался просто показать вам путь, потому что я действительно не могу опубликовать их в этом ответе.
Здесь - полная информация и инструкции.
Надеюсь, что этот ответ будет полезен и поможет вам.
Ответ 2
Вы можете использовать html-метод @Html.RenderPartial(_CreateFormField.cshtml) внутри вашей родительской страницы cshtml.
Для информации о режиме http://msdn.microsoft.com/en-us/library/dd492962(v=vs.118).aspx
Я предоставляю пример псевдокода,
@Foreach(childModel in model.FormFields)
{
@Html.RenderPartial("childView.cshtml","Name", childModel)
}
Пожалуйста, попробуйте его в правильном С# синтаксическом ключе, и вы получите частичные представления, отображаемые для каждого элемента коллекции.
Ответ 3
Проблема заключается в том, что ваше частичное представление должно использовать:
@model Form //Instead of FormField
а затем внутри частичного представления вы должны использовать модель model = > . FormField.x
<div class="editor-label">
@Html.LabelFor(model => model.FormField.Name)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.FormField.Name)
@Html.ValidationMessageFor(model => model.FormField.Name)
</div>
Это работает только для отношений "один-к-одному" (или так я читаю в этом потоке: здесь). Также не имеет значения, есть ли у вас @Html.Form внутри частичного представления.
После внесения этих изменений у меня не возникло проблем с возвратом всех опубликованных данных в контроллер.
РЕДАКТИРОВАТЬ: У меня возникли проблемы с этим, как скоро кто-то выяснит.
Лучший способ сделать это (что я видел) вместо этого использовать EditorTemplate. Таким образом, редактор остается независимым от родителя, и вы можете добавить форму на любую страницу, а не просто страницу, где вы также добавляете FormField.
Затем вы заменили
@Html.Partial("view")
с
@Html.EditorFor()
В принципе, я выяснил, что лучше использовать @Html.EditorFor вместо частичного представления при редактировании (это называется представлением, а не редактором).
Ответ 4
Если вы хотите использовать макет сетки, вы можете попробовать сетку пользовательского интерфейса Kendo
Ответ 5
Используйте jQuery для добавления FormField при нажатии кнопки.
Аналогично я использовал его следующим образом
<div class="accomp-multi-field-wrapper">
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>FormId</th>
<th>Remove</th>
</tr>
</thead>
<tbody class="accomp-multi-fields">
<tr class="multi-field">
<td> <input name="FormFields[0].Name" type="text" value=""></td>
<td> <input name="FormFields[0].FormId" type="text" value=""></td>
<td> <button type="button" class="remove-field">X</button></td>
</tr>
</tbody>
<tr>
<th><button type="button" class="add-field btn btn-xs btn-primary addclr"><i class="fa fa-plus"></i> Add field</button> </th>
</tr>
</table>
</div>
и jQuery для добавления поля и удаления
<script>
$('.accomp-multi-field-wrapper').each(function () {
var $wrapper = $('.accomp-multi-fields', this);
$(".add-field", $(this)).click(function (e) {
var $len = $('.multi-field', $wrapper).length;
$('.multi-field:first-child', $wrapper).clone(false, true).appendTo($wrapper).find('select,input,span').val('').each(function () {
$(this).attr('name', $(this).attr('name').replace('\[0\]', '\[' + $len + '\]'));
});
$(document).on("click",'.multi-field .remove-field', function () {
if ($('.multi-field', $wrapper).length > 1) {
$(this).closest('tr').remove();
//
$('.multi-field', $wrapper).each(function (indx) {
$(this).find('input,select,span').each(function () {
$(this).attr('name', $(this).attr('name').replace(/\d+/g, indx));
})
})
}
});
</script>
Надеюсь, что это поможет вам.