So, I have a referral form for job application. Now when a job seeker selects a company from a company dropdown, I want to display the dropdown of coverletters just for that company (coverletters are already uploaded by candidate from another tab). Now for getting referred for Microsoft a person might have 3 coverletters.
Issue:
I want to know how to can I display the dropdown from ajax call and still keep the coverletter dropdown strongly bound to the Model.
Below is Non AJAX strongly Bound: shows all the coverletters irrespective of company selected)
View:
@model Bridge.ViewModels.ReferralViewModel
@using (Html.BeginForm())
{
<div class="form-group">
@Html.LabelFor(model => model.CompanyId, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownListFor(m => m.CompanyId, Model.Companies, new { @class = "form-control js-change", onchange = "companyChanged()" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.CoverLetterId, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownListFor(m => m.CoverLetterId, new SelectList(Model.CoverLetters, "CoverLetterId", "CoverLetterName", Model.CoverLetters), new { @class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
Model:
public class ReferralViewModel
{
public int ReferralViewModelId { get; set; }
public int CompanyId { get; set; }
public IEnumerable<SelectListItem> Companies { get; set; }
public int CoverLetterId { get; set; }
public IEnumerable<CoverLetter> CoverLetters { get; set; }
}
Controller:
public ActionResult Create()
{
var viewModel = new ReferralViewModel
{
var candidateId = User.Identity.GetUserId();
Companies = _context.Companies.Select(x => new SelectListItem
{
Text = x.CompanyName,
Value = x.CompanyId.ToString()
}),
CoverLetters = _context.CoverLetters.Where(r => r.CandidateId == candidateId).ToList()
};
return View(viewModel);
}
Now AJAX Attempt:
Controller Action
public JsonResult ListOfCoverLetterByCompanyId(int companyId)
{
var coverletters = _context.CoverLetters
.Where(c => c.CompanyId == companyId)
.ToList();
var dropdown = new List<SelectListItem>();
foreach (var cl in coverletters)
{
dropdown.Add(new SelectListItem { Text = cl.CoverLetterName, Value = cl.CoverLetterId.ToString() });
}
return Json(dropdown, JsonRequestBehavior.AllowGet);
}
New View
@model Bridge.ViewModels.ReferralViewModel
@using (Html.BeginForm())
{
@Html.LabelFor(model => model.CompanyId, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownListFor(m => m.CompanyId, Model.Companies, new { @class = "form-control js-change", onchange = "companyChanged()" })
</div>
</div>
@* Dropdown will appear here*@
<select id="CoverLetterId" name="CoverLetterId"></select>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
@section scripts{
<script>
function companyChanged() {
var companyId = $(".js-change").val();
$.ajax({
url: "/Referral/ListOfCoverLetterByCompanyId",
data: { companyId: companyId },
contentType: "application/json; charset-utf-8",
success: function (datas) {
$("#CoverLetterId").html("");
$.each(datas, function (i, data) {
$("#CoverLetterId ").append('<option value="' + data.Value + '">' + data.Text + '</option>');
});
},
error: function () {}
});
}
</script>
<script>
companyChanged();
</script>
}
New View Model
public class ReferralViewModel
{
public int ReferralViewModelId { get; set; }
public int CompanyId { get; set; }
public IEnumerable<SelectListItem> Companies { get; set; }
public int CoverLetterId { get; set; }
}
I think by following current code I lost the beauty of strongly bound Razor view. Dropdown is not bound to any property. Can I somehow make it strongly bound and use @Html.DropdownListFor
if all you want is strong type generating the
select
html, you could callDropDownListFor
with a empty optionsthen reset code remain the same
the
select
created will have correct name which means model binding will work properlyYour original view model is correct although it would be better for your
CoverLetters
property to bepublic IEnumerable<SelectListItem> CoverLetters { get; set; }
, and both theCompanyId
andCoverLetterId
properties should beint?
(nullable)and in the view, strongly bind to your model using
In your controller, add a private method that initializes both SelectLists. If
CompanyId
has a value, then your populateCoverLetters
from the database, otherwise you initialize it to an empty collection. You can then call that method in both the GET method, and in the POST method ifModelState
is invalid