Nested Collection Models in MVC to Add Multiple Phone Numbers - Part 1
In
this article series, you will learn how to create MVC application
that will allow adding multiple phone numbers using Nested Model Concept. User
will be able to add or remove (zero or more phone numbers, I need minimum two phone numbers for each employee) phone numbers for any single
employee. Also in later posts, I will show you how to List, Edit, Delete record(s) in such nested (relational) models concept. Here is the first look of the concept.
Now,
I will go step by step so that you can understand what is going on.
Step 1: Database
First
thing first you need is database tables with proper relationship. The main
concept is, there will be none or more Phone Numbers in ‘Phone’ table for each
Employee in ‘Employee’ table.
Note,
we have navigation properties in both tables and ‘EmployeeId’ in Phone table
for each phone numbers.
You
will find a property ‘DeletePhone’ in Phone table, this property will be used
as a flag to delete contact number by controller method when user marked for
deletion on View. Actually, this field is not required in database table when
you have ViewModel class, and this is a quick demo so rather creating a class I
will prefer adding property in database table.
I
will share the script file to generate this database at the end of this
article. I am using Entity Data Model to generate model classes and DbContext.
Once you done with this, move to next step.
Step 2: Prepopulating
Collection (Phone Number input boxes)
In
the very first animated image, you can see page gets loaded with two ‘Phone
Number’ input boxes. To do this I need to update ‘Employee’ model (this model
is generated by Entity Data Model) with following highlighted method.
public partial class Employee
{
public Employee()
{
this.Phones = new HashSet<Phone>();
}
public int EmployeeId { get; set; }
public string Name { get; set; }
public string Salary { get; set; }
public virtual ICollection<Phone> Phones { get; set; }
internal void CreatePhoneNumbers(int count = 1)
{
for (int i = 0; i < count; i++) {
Phones.Add(new Phone());
}
}
}
This
highlighted method ‘CreatePhoneNumbers’ will take a parameter and add that
collection to ‘Phones’ model property.
Now,
let’s add a new controller ‘Employee’ and an action method ‘Add’ and then we
will make a call to above highlighted method, here you go.
public ActionResult New()
{
var employee = new Employee();
employee.CreatePhoneNumbers(2);
return View(employee);
}
I
just created the object of Employee model class and making a call to
‘CreatePhoneNumbers’ method with 2 as a parameter, this will help in generating
two input boxes on the View page. Add the View Page for this Action method.
Step 3: Creating
View
Creating
View for above employee model is also simple. Let’s update the view page you
added in above step by following code.
New.cshtml
@{
ViewBag.Title = "New";
}
<h2>Add New Employee</h2>
@using (Html.BeginForm()){
@Html.AntiForgeryToken()
@Html.EditorForModel()
<p>
<button type="submit">Create Employee</button>
</p>
}
If
you run this view here, you will see following output.
So,
I will call this view page template-less. You can see I am using EditorForModel(),
this will look at the type of model, then go looking for available templates in
EditorTemplates folder for a file named Employee.cshtml that we don’t have. Let’s
add a new View page at the location
Views|Employee|EditorTemplates|Employee.cshtml and add following code.
Employee.cshtml
@model
NestedModelsMvc.Models.Employee
@Html.HiddenFor(x => x.EmployeeId)
<p>
<label>Name</label>
@Html.TextBoxFor(x => x.Name)
</p>
<p>
<label>Salary</label>
@Html.TextBoxFor(x => x.Salary)
</p>
<div id="phoneNumbers">
@Html.EditorFor(x => x.Phones)
</div>
Now,
again inside Employee.cshtml, we have a EditorFor(). This will again look at
the type of model, then go looking for available templates in EditorTemplates
folder for a file named Phone.cshtml that we don’t have. Let’s add this too.
Phone.cshtml
@model
NestedModelsMvc.Models.Phone
<div class="phoneNumber">
<p>
<label>Phone Number</label>
@Html.TextBoxFor(x => x.PhoneNumber)
@Html.HiddenFor(x => x.DeletePhone, new { @class = "mark-for-delete"
})
</p>
</div>
Now,
let me show you the view files so that you don’t confuse with the view file placements.
Now
we are ready to run the New.cshtml file to look at the generated UI.
Great
Start! Let’s look at the generated HTML markups.
In
above HTML markup, you can see two div tags that has class="phoneNumber"
and inside that we have two input fields.
First
field which is generated by TextBoxFor(x => x.PhoneNumber) has type="text"
where user will enter phone number. And second field which is generated by HiddenFor(x
=> x.DeletePhone, new { @class = "mark-for-delete" }) has type="hidden"
which will work as flag whether to delete or not.
Notice,
we called EditorFor(x => x.Phones) in Employee.cshtml and it looped through
our phone numbers and created two nested editors and each editor has format
defied in Phone.cshtml and see how smartly id and name attributes filled up
with index based words.
You
can also notice the value attribute is blank, this will be filled with value="True"
when user will mark for deletion. So, if value is blank we don’t need to
execute delete query, you will see it later.
Step 4: Deleting
Phone Number
You
will learn this step in Part 2.
Hope
this helps.
Nice feature man
ReplyDeleteThis is nice concept but i want to implement its on asp.net without use MVC
ReplyDeleteThan please give me solution
Please provide source code. At the end of this article the mentioned url is invalid.
ReplyDeletewhat if am using a dropdownlist instead of the phone textbox, how to populate the dropdownlist in the phone.cshtml
ReplyDeleteThis is a wonderful article. My data is in another project which is reference but when i add the internal void CreatePhonenumbers it is not recognized as being a part of my class. is there an issue if the Model is in a separate project?
ReplyDeletegreat
ReplyDeleteGreat, simple explanation... Thank you!
ReplyDeletehi
ReplyDeletei have small doubt
saved the same data same two tables and updated the data in one
table using mvc
could please explain