Reputation: 4009
I have a requirement to be able to dynamically add/remove rows to a Tabel in an MVC 5 Application I am working on. I have also included knockout in my project as I use it to post back to preform calculation on my viewModel.
What I have done so far is created a List on my User Model to hold the details of the AdditionalUsers:
public List<AdditionalUser> AdditionalUsers { get; set; }
Additional User class defined as:
public class AdditionalUser
{
public string FirstName { get; set; }
public string Surname { get; set; }
public double Cost { get; set; }
}
I then created a EditorTemplates folder and created a partial view _AdditionalUser.cshtml as below:
@model MyProject.Models.AdditionalUser
<td>
@Html.TextBoxFor(model => model.FirstName)
</td>
<td>
@Html.TextBoxFor(model => model.Surname)
</td>
<td>
@Html.TextBoxFor(model => model.Cost)
</td>
Where I need this rendered on my User View I have done the following:
<tr>
@Html.EditorFor(model => model.AdditionalUsers)
</tr>
Each other on the view has 3 . Doing this then in my controller where I new my User model I did:
model.AdditionalUsers = new List<AdditionalUser>(2);
I would have thought that would have created two blank rows in the tr where I called EditorFor but nothing is rendered? This was just for my first test to get the EditorTemplate working. I want to then wire this up to knockout to Add and remove the rows dynamically but first I am wondering why the EditorTemplate is not rendering as expected?
Upvotes: 3
Views: 1345
Reputation: 118947
Your editor template is named incorrectly. There are two ways for MVC to pick it up:
By Name
Name the template with the exact same name as the data type:
DateTime.cshtml
String.cshtml
AdditionalUser.cshtml
Explicitly
In the property of your model, use the UIHint
attribute:
public class MyModel
{
public SomeObject TheObject { get; set; }
[UIHint("SomeObject")]
public SomeObject AnotherObject { get; set; }
}
Additionally your code is not quite correct to get the rows rendered. You should first add the tr
tag to the view:
@model MyProject.Models.AdditionalUser
<tr>
<td>
@Html.TextBoxFor(model => model.FirstName)
</td>
<td>
@Html.TextBoxFor(model => model.Surname)
</td>
<td>
@Html.TextBoxFor(model => model.Cost)
</td>
</tr>
Next change your parent view to something like this (note I've added table header row for clarity):
<table>
<tr>
<th>@Html.DisplayNameFor(m => m.FirstName)</th>
<th>@Html.DisplayNameFor(m => m.Surname)</th>
<th>@Html.DisplayNameFor(m => m.Cost)</th>
</tr>
@Html.EditorFor(model => model.AdditionalUsers)
</table>
Upvotes: 1
Reputation: 284
You can drop the "_" character from the name, or there is an overload, that takes a template name as the second argument.
@Html.EditorFor(model => model.AdditionalUsers, "_AdditionalUsers")
Upvotes: 1
Reputation: 3061
here is the rules
1- the name of the template must be same. in your case it must be AdditionalUser.cshtml 2- MVC first looks if a folder EditorTemplates exists in the parent folder of the view (which has controller name) then looks at Shared folder.
But in your case @Html.EditorFor(model => model.AdditionalUsers)
is would not work as the type is List and as far as I know there is no way to do that so use a foreach loop;
@foreach (var u in model.AdditionalUsers) {
@Html.EditorFor(model => u)
}
should do the trick.
Upvotes: 0
Reputation: 218732
In your GET action method, you need to return some item in the AdditionalUsers
collection. Try this.
var yourViewModel=new YourViewModel();
var userList = new List<AdditionalUser>();
userList.Add(new AdditionalUser { FirstName ="A"} );
userList.Add(new AdditionalUser{ FirstName ="B"});
yourViewModel.AdditionalUsers =userList();
return view(yourViewModel);
Also your editor template name should be same as the class name which is strongly typed to the editor template razor view, which is AdditionalUser.cshtml
Upvotes: 0