0

Basically i have a editor view where i have a few fields and a list, located in admin -> teacher -> edit

File.cshtml

<fieldset>
    <legend>@T("Details")</legend>
    @Html.LabelFor(m => m.FirstName, T("First name"))
    @Html.TextBoxFor(m => m.FirstName)
    @Html.LabelFor(m => m.LastName, T("Last name"))
    @Html.TextBoxFor(m => m.LastName)
    @Html.LabelFor(m => m.Gender, T("Gender"))
    @Html.DropDownListFor(m => m.Gender, genderSelectListItems, "Select gender...")
</fieldset>

<fieldset>
@{
    var i = 0;
    @Html.LabelFor(m => m.Availability)
    @Html.DropDownListFor(m => m.Availability, daysSelectList, "Select day to add...")
    <input type="button" id="addDay" value="Add" />
    <ul id="daysList">
        @foreach (var day in Model.Availability)
        {
            <li>
                @Html.TextBoxFor(m => m.Availability[i].Interval)
            </li>
            i++;
        }
    </ul>
}
</fieldset>

Whenever i submit the data, only the fields get saved. The list is never saved, even though fiddler shows that the data is sent back to the server

My models are:
TeacherPartRecord

public class TeacherPartRecord : ContentPartRecord
{
    public TeacherPartRecord()
    {
        TeacherData = new List<TeacherDataRecord>();
    }

    public virtual string FirstName { get; set; }
    public virtual string LastName { get; set; }
    public virtual Gender Gender { get; set; }

    public virtual IList<TeacherDataRecord> TeacherData { get; set; }
}

TeacherPart - this file is almost the same as TeacherPartRecord so i truncated it, showing only the difference

public class TeacherPart : ContentPart<TeacherPartRecord>
{
      ................  
    public IList<AvailabilityRecord> Availability
    {
        get { return Record.TeacherData.Select(r => r.AvailabilityRecord).ToList(); }
    }
}

TeacherDataRecord

public class TeacherDataRecord
{
    public virtual int Id { get; set; }
    public virtual TeacherPartRecord TeacherPartRecord { get; set; }
    public virtual AvailabilityRecord AvailabilityRecord { get; set; }
}

AvailabilityRecord

public class AvailabilityRecord
{
    public virtual int Id { get; set; }
    public virtual Day Day { get; set; }
    public virtual string Interval { get; set; }
}

and TeacherPartDriver

public class TeacherPartDriver : ContentPartDriver<TeacherPart>
{
    //GET
    protected override DriverResult Editor(TeacherPart part, dynamic shapeHelper)
    {
        return ContentShape("Parts_Teacher_Edit", () => 
            shapeHelper.EditorTemplate(TemplateName: "Parts/Teacher", Model: BuildEditorViewModel(part), Prefix: Prefix));
    }

    //POST
    protected override DriverResult Editor(TeacherPart part, IUpdateModel updater, dynamic shapeHelper)
    {
        var viewModel = new TeacherEditViewModel();
        updater.TryUpdateModel(viewModel, Prefix, null, null);
        _teacherService.UpdateTeacher(viewModel, part);
        return Editor(part, shapeHelper);
    }
}

BuildEditorViewModel only maps properties from TeacherPart to TeacherEditViewModel, which is identical with TeacherPart

The POST Editor method never receives the data from Availability (part.Availability is the same as previously, new data is not received)

I inserted a few entries in the database manually because i can't add a list of type Availability from the edit page, even though the other content (first name, last name, gender) is created

I would like to know how/when does the binding occur, or maybe some suggestions on how i could solve this issue.

I should mention that my c#/MVC experience is 6 months and my orchard experience is about 2 weeks so i'm still learning. All i hope is that i stated my problem clearly and there is someone that can help. Thank you for your time

EDIT As i can see, the values are bound

<input id="Teacher_Availability_0__Interval" name="Teacher.Availability[0].Interval" type="text" value="14-20">
<input id="Teacher_Availability_1__Interval" name="Teacher.Availability[1].Interval" type="text" value="12-18">

and fiddler shows the data is getting sent

Fiddler

so i guess that something wrong happens right after the data is sent and before being received by the server or maybe my models are wrong

Ionuț
  • 21
  • 5
  • You cannot use a `foreach` loop to generate form controls for a collection. You need a `for` loop of `EditorTemplate`. Refer [this answer](http://stackoverflow.com/questions/30094047/html-table-to-ado-net-datatable/30094943#30094943) –  May 24 '16 at 13:28
  • But he uses and increments a counter nonetheless, so the html should be valid. @Ionuț can you confirm the rendered html for #daysList is valid? – Xceno May 24 '16 at 13:42
  • Yes, the html is correct, and the data is sent back to the server. And that is the moment when something somewhere goes wrong and i don't get what I will edit my post showing fiddler – Ionuț May 24 '16 at 13:45
  • You said that *TeacherEditViewModel* is identical to TeacherPart, which doesn't have a setter on *Availability*. That might be a problem. If it's not 100% identical, can you please post the ViewModel too? – Xceno May 24 '16 at 15:02
  • I repeat again - do not use a `foreach` loop. And you have multiple other issues such as `Availability` does not have a setter, so its values cannot be set by the `DefaultModelBinder` and you you have a dropdownlist for `Availability` and you cannot bind a ` –  May 24 '16 at 23:31
  • @Xceno The ViewModel is `public class TeacherEditViewModel { public string FirstName { get; set; } public string LastName { get; set; } public Gender Gender { get; set; } public IList Availability { get; set; } }` Stephen, i will try what you said and get back to you – Ionuț May 25 '16 at 06:18
  • @StephenMuecke adding a setter to the `Availability` and a for loop does not solve the issue. Still the same result. As for the DropDown, ignore it for a second, first i want to make it work and after that, add more elements to the list. – Ionuț May 25 '16 at 06:43
  • You cant 'ignore' the dropdownlist - its binding to property `Avaliability` do if its value is say `1` then the `DefaultModelBinder` will try to do `model.Avaliability = 1;` which of course fails. You need to delete it from the view. And adding the setter is essential because without it, binding will also fail. –  May 25 '16 at 06:48
  • It seems that there were no issues. all i had to do was map the part to the ViewModel in the service and update/create database entries. Thank you both for your time. VS debugger wasn't showing the updated data until i wrote the mappings. So for that matter, i still don't get it how it works – Ionuț May 25 '16 at 08:49

0 Answers0