2016-02-19 1 views
1

У меня есть модель, которая имеет сложный тип как свойство. Я создал пользовательский DisplayEditor для сложного типа дочернего элемента, и он корректно связан с загрузкой страницы. Когда страница публикуется после внесения изменений, тип Dependents устанавливается равным null. Вот код для модели Сотрудника, который представляет ребенка иждивенцы свойство:Custom EditorTemplate не возвращает значения формы Правильно

[Display(Name = "Dependents")] 
[DataType(DataType.MultilineText)] 
public List<Dependent> Dependents { get; set; } 

Вот Зависимая модель:

[Serializable] 
public class Dependent : Person 
{ 
    public Dependent() 
    { 
     Deduction deduction = new Deduction(this) { Amount = Constants.DependentDeductionAmount }; 
     this.Deduction = deduction; 
    } 

    [Key] 
    [HiddenInput(DisplayValue = false)] 
    public int DependentId { get; set; } 

    [Required] 
    [Display(Name = "Dependent Type")] 
    public DependentType DependentType { get; set; } 

    [Required] 
    public override double DeductionAmount => Constants.DependentDeductionAmount; 
} 

Методы действий 2 редактирования на контроллере сотрудника (я пробовал TryUpdateModel , не работает):

public ViewResult Edit(int employeeId) 
    { 
     if (employeeId < 0) throw new ArgumentOutOfRangeException(nameof(employeeId)); 

     Employee employee = _employeeRepository.Employees.FirstOrDefault(e => e.EmployeeId == employeeId); 

     bool result = TryUpdateModel(employee, new FormValueProvider(ControllerContext)); 

     return View(employee); 
    } 

    [HttpPost] 
    public ActionResult Edit(Employee employee) 
    { 
     if (employee == null) throw new ArgumentNullException(nameof(employee)); 

     if (ModelState.IsValid) 
     { 
      employee.Changed = true; 
      employee.Dependents.ForEach(d => d.Changed = true); 
      _employeeRepository.SaveEmployee(employee); 
      TempData["message"] = $"{employee} has been saved."; 
      return RedirectToAction("Index"); 
     } 
     else { 
      // there is something wrong with the data values 
      return View(employee); 
     } 
    } 

Вот Edit.cshtml:

@model Paylocity.HR.Domain.Entities.Employee 

@{ 
    ViewBag.Title = $"{"Edit"} {Model}"; 
} 

<div class="panel panel-default"> 
    <div class="panel-heading"> 
     <h3>@ViewBag.Title</h3> 
</div> 
@using (Html.BeginForm("Edit", "Employee")) 
{ 
    @Html.AntiForgeryToken() 

    <div class="form-horizontal"> 
     <hr/> 
     @Html.ValidationSummary(true, "", new {@class = "text-danger"}) 
     <h4>Employee</h4> 
     <div class="form-group"> 
      @Html.LabelFor(model => model.FirstName, htmlAttributes: new {@class = "control-label col-md-2"}) 
      <div class="col-md-10"> 
       @Html.EditorFor(model => model.FirstName, new {htmlAttributes = new {@class = "form-control"}}) 
       @Html.ValidationMessageFor(model => model.FirstName, "", new {@class = "text-danger"}) 
      </div> 
     </div> 
     <div class="form-group"> 
      @Html.LabelFor(model => model.LastName, htmlAttributes: new {@class = "control-label col-md-2"}) 
      <div class="col-md-10"> 
       @Html.EditorFor(model => model.LastName, new {htmlAttributes = new {@class = "form-control"}}) 
       @Html.ValidationMessageFor(model => model.LastName, "", new {@class = "text-danger"}) 
      </div> 
     </div> 
     <hr/> 
     @Html.EditorFor(model => model.Dependents, "Dependents") 
     @Html.HiddenFor(model => model.EmployeeId) 
    </div> 
    <div class="panel-footer"> 
     <input type="submit" value="Save" class="btn btn-primary"/> 
     @Html.ActionLink("Cancel and return to List", "Index", null, new {@class = "btn btn-default"}) 
    </div> 
} 
</div> 

Вот Dependent.cshtml EditorTemplate:

@model IEnumerable<Dependent> 
@using Paylocity.HR.Domain.Entities 

@foreach (var dep in Model) 
{ 
<h4>Dependent</h4> 
<div class="form-group"> 
    @Html.LabelFor(m => dep.FirstName, htmlAttributes: new { @class = "control-label col-md-2" }) 
    <div class="col-md-10"> 
     @Html.EditorFor(m => dep.FirstName, new { htmlAttributes = new { @class = "form-control" } }) 
     @Html.ValidationMessageFor(m => dep.FirstName, "", new { @class = "text-danger" }) 
    </div> 
</div> 
<div class="form-group"> 
    @Html.LabelFor(m => dep.LastName, htmlAttributes: new { @class = "control-label col-md-2" }) 
    <div class="col-md-10"> 
     @Html.EditorFor(m => dep.LastName, new { htmlAttributes = new { @class = "form-control" } }) 
     @Html.ValidationMessageFor(model => dep.LastName, "", new { @class = "text-danger" }) 
    </div> 
</div> 
<div class="form-group"> 
    @Html.LabelFor(m => dep.DependentType, htmlAttributes: new { @class = "control-label col-md-2" }) 
    <div class="col-md-10"> 
     @Html.EnumDropDownListFor(m => dep.DependentType, new { @class = "form-control" }) 
     @Html.ValidationMessageFor(m => dep.DependentType, "", new { @class = "text-danger" }) 
    </div> 
</div> 
<hr /> 
} 

объект Сотрудник связывает правильно и изменяемым, это только тип иждивенцы ребенок, который не связан правильно. HTML отображает правильные идентификаторы/имена полей зависимой формы (я верю?). Нужно ли мне реализовать какой-то пользовательский код связующего, или я пропущу что-то очевидное здесь?

Это мой первый вопрос о СО, надеюсь, я предоставил достаточно информации.

ответ

0

Изменить модель в Dependent.cshtml шаблон @model Dependent (он не может быть IEnumerable<T>) и удалить цикл foreach, который генерирует name атрибутов, которые не имеют никакого отношения к вашей модели (и дублируют id атрибутов, недопустим HTML)

Она также нуждается быть расположена в /Views/Shared/EditorTemplates/ или /Views/yourControllerName/EditorTemplates/ папку

@model Dependent 
... 
@Html.EditorFor(m => m.FirstName, new { htmlAttributes = new { @class = "form-control" } }) 
... 
@Html.EditorFor(m => m.LastName, new { htmlAttributes = new { @class = "form-control" } }) 

и т.д. Затем в главном окне, используйте

@Html.EditorFor(model => model.Dependents) 

EditorFor() метод принимает IEnumerable<T> и будет генерировать правильный HTML для каждого элемента в коллекции, включая правильную name атрибуты с индексаторами

+0

Мне показалось, что я уже пробовал этот подход (изменяя EditorTemplate, чтобы не использовать коллекцию, и привязывать непосредственно к коллекции в основном представлении), но, видимо, я этого не сделал или пропустил что-то в этом процессе. Это ответ, я знал, что это будет что-то простое. Спасибо! –

0

Я думаю, что ваша проблема в том, как вы генерируете список предметов.

использовать индекс вместо foreach.

, следовательно, ваш Dependent.cshtml EditorTemplate

сделать что-то вроде:

@for(int i = 0; i < Model.Count(); i++) 
{ 
<h4>Dependent</h4> 
<div class="form-group"> 
    @Html.LabelFor(m => Model[i].FirstName, htmlAttributes: new { @class = "control-label col-md-2" }) 
    <div class="col-md-10"> 
     @Html.EditorFor(m => Model[i].FirstName, new { htmlAttributes = new { @class = "form-control" } }) 
     @Html.ValidationMessageFor(m => Model[i].FirstName, "", new { @class = "text-danger" }) 
    </div> 
</div> 

// rest field follow same pattern 
} 

для получения дополнительной информации о списке привязки, проверка этой пост http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/

+0

Это тоже сработало бы. Упрек, но, отмечая, что Стивен в качестве ответа b/c, он чище. Спасибо хоть! –

+0

На самом деле это не сработало бы. Для использования цикла 'for' модель должна быть' IList ''. –

Смежные вопросы