I have a client needs to be able to create candidates. Candidates can have many qualifications (qualifications is model with 4 properties). The client needs to be able to add N numbers of qualifications to the employee on the creation page.
View Model
public class CreateCandidateViewModel
{
[DisplayName("First Name"), Required]
public string FirstName { get; set; }
[DisplayName("Last Name"), Required]
public string LastName { get; set; }
[DisplayName("Email Address"), Required]
public string Email { get; set; }
[DisplayName("Phone Number"), Required]
public string Phone { get; set; }
[DisplayName("Zip Code"), Required]
public int ZipCode { get; set; }
public List<Qualification> Qualifications { get; set; }
}
Qualification Model
public class Qualification
{
[Key]
public int Id { get; set; }
public int QualificationTypeId { get; set; }
public string Name { get; set; }
public DateTime DateStarted { get; set; }
public DateTime DateCompleted { get; set; }
[ForeignKey("QualificationTypeId")]
public virtual QualificationType Type { get; set; }
}
I have no idea how to approach this problem. I was thinking of creating the candidate first and then sending the client to another view where the client can add qualifications and so on.
Stephen mentioned in a comment that you will likely need to use javascript or jquery to accomplish this if you want to keep your user on the same page.
I am assuming your post controller is expecting a CreateCandidateViewModel
It is possible to do model binding when your model has a property of a list of objects, so long as the naming on the inputs is correct when the form is submitted. The key is indexing the names on the inputs:
<input type="text" name="Qualifications[0].Id" />
<input type="text" name="Qualifications[0].QualificationTypeId" />
<input type="text" name="Qualifications[0].Name" />
<input type="text" name="Qualifications[0].DateStarted" />
<input type="text" name="Qualifications[0].DateCompleted" />
<input type="text" name="Qualifications[1].Id" />
<input type="text" name="Qualifications[1].QualificationTypeId" />
<input type="text" name="Qualifications[1].Name" />
<input type="text" name="Qualifications[1].DateStarted" />
<input type="text" name="Qualifications[1].DateCompleted" />
This will correctly bind to your model on submit. Be mindful of resetting the indexies when removing a "qualification" after it was added, or you may get null objects in your list, or missing objects. I've done this successfully before with JQuery and regular expressions.
If you want to go the Ajax way, you could create a partial view and call that using AJAX.
Controller
public ActionResult QualificationsPartial(Int32 Index)
{
return PartialView(model:Index);
}
Partial View
@model Int32
<input type="text" name="Qualifications[@Model.ToString()].Id" />
<input type="text" name="Qualifications[@Model.ToString()].QualificationTypeId" />
<input type="text" name="Qualifications[@Model.ToString()].Name" />
<input type="text" name="Qualifications[@Model.ToString()].DateStarted" />
<input type="text" name="Qualifications[@Model.ToString()].DateCompleted" />
Ajax on Main View
var QualificationIndex = parseInt(1); // 1 because we already have 0 loaded
$("#AddQualificationElement").click(function () {
$.ajax({
cache: false,
type: "GET",
url: "/MyController/QualificationsPartial",
data: {
Index: QualificationIndex
},
success: function (data) {
// data will be the html from the partial view
$("#QualificationsContainer").append(data);
},
error: function (xhr, ajaxOptions, thrownError) {
// Handle the error somehow
}
}); // end ajax call
}); // end AddQualificationElement click event