I am writing an ASP.NET MVC4 / Razor / C# based application that needs to render a grid of records. Each row has several columns, and there may be 100 or so rows.
Each row has a checkbox field, text field and then three cascading dropdown lists. The first dropdown is prepopulated on page load. The second needs to be populated using Ajax on change of the first dropdown list. The third from a change on the second. Each row is separate and does not influence each other.
What is the recommended way to implement something like this? The various solutions for cascading dropdown lists are only for single cascading lists - they do not work (for me) when placed inside a foreach loop.
The skeleton of what I have is shown below:
@model IList<MyModel>
@using (Html.BeginForm("MyAction", "Home")) {
<table><tr><th>Use?</th><th>Name</th><th>List A</th><th>List B</th><th>List C</th></tr>
@Html.EditorForModel()
</table>
}
The model looks something like this:
public class MyModel
{
public bool Use { get; set; }
public string Name { get; set; }
public int? ListAId { get; set; }
public int? ListBId { get; set; }
public int? ListCId { get; set; }
public IList<ListAList> ListA { get; set; }
}
The shared EditorTemplates file MyModel.cshtml follows this structure:
@model MyNamespace.MyModel
<tr>
<td>@Html.CheckBoxFor(model => model.Use)</td>
<td>@Html.DisplayFor(model => model.Name)</td>
<td>@Html.DropDownListFor(model => model.ListAId, new SelectList(Model.ListA, "Id", "Name", Model.ListAId), "")</td>
<td>??</td>
<td>??</td>
</tr>
The ?? indicates I am unsure what to put in here.
How do I proceed to render the ListB select box using Ajax on change of the ListA select box, then on change of ListB render the ListC select box?
check this:
- on select change event - Html.DropDownListFor
- http://addinit.com/node/19
or
- http://www.codeproject.com/Articles/258172/Simple-Implementation-of-MVC-Cascading-Ajax-Drop-D
Update1: Suppose that there is Name ROWID, (and list all the same data source).
Update2: the example available on github
Based on these responses:
- How to populate a @html.dropdownlist mvc helper using JSon
- Populate a <select></select> box with another
Model:
using System.Collections.Generic;
namespace MyNamespace
{
public class MyModel
{
public MyModel() { ListA = new List<ListAList>(); }
public bool Use { get; set; }
public string Name { get; set; }
public int? ListAId { get; set; }
public int? ListBId { get; set; }
public int? ListCId { get; set; }
public IList<ListAList> ListA { get; set; }
}
public class ListAList
{
public int Id { get; set; }
public string Name { get; set; }
}
}
Main action in the Home Controller:
public ViewResult MyAction()
{
var model = new List<MyModel>();
for (int i = 0; i < 10; i++)
{
var item = new MyModel()
{
Name = string.Format("Name{0}", i),
Use = (i % 2 == 0),
ListAId = null,
ListBId = null,
ListCId = null
};
for (int j = 0; j < 10; j++)
{
item.ListA.Add( new ListAList()
{
Id=j,
Name = string.Format("Name {0}-{1}",i,j)
});
}
model.Add(item);
}
return View(model);
}
Data source provider in the Home controller:
public JsonResult PopulateOption(int? listid, string name)
{
//todo: preparing the data source filter
var sites = new[]
{
new { id = "1", name = "Name 1" },
new { id = "2", name = "Name 2" },
new { id = "3", name = "Name 3" },
};
return Json(sites, JsonRequestBehavior.AllowGet);
}
EditorTemplate:
@model MyNamespace.MyModel
<tr>
<td>@Html.CheckBoxFor(model => model.Use)</td>
<td>@Html.DisplayFor(model => model.Name)</td>
<td>@Html.DropDownListFor(model => model.ListAId, new SelectList(Model.ListA, "Id", "Name", Model.ListAId), "", new { @id = string.Format("ListA{0}", Model.Name), @class="ajaxlistA" })</td>
<td><select class="ajaxlistB" id="ListB@(Model.Name)"></select></td>
<td><select class="ajaxlistC" id="ListC@(Model.Name)"></select></td>
</tr>
And the main view with Ajax functions:
@using MyNamespace
@model IList<MyModel>
@using (Html.BeginForm("MyAction", "Home")) {
<table><tr><th>Use?</th><th>Name</th><th>List A</th><th>List B</th><th>List C</th></tr>
@Html.EditorForModel()
</table>
}
<script src="@Url.Content("~/Scripts/jquery-1.7.1.js")" type="text/javascript"></script>
<script>
$(document).ready( $(function () {
$('.ajaxlistA').change(function () {
// when the value of the first select changes trigger an ajax request
list = $(this);
var listvalue = list.val();
var listname = list.attr('id');
$.getJSON('@Url.Action("PopulateOption", "Home")', { listid: listvalue, name: listname }, function (result) {
// assuming the server returned json update the contents of the
// second selectbox
var listB = $('#' + listname).parent().parent().find('.ajaxlistB');
listB.empty();
$.each(result, function (index, item) {
listB.append(
$('<option/>', {
value: item.id,
text: item.name
})
);
});
});
});
$('.ajaxlistB').change(function () {
// when the value of the first select changes trigger an ajax request
list = $(this);
var listvalue = list.val();
var listname = list.attr('id');
$.getJSON('@Url.Action("PopulateOption", "Home")', { listid: listvalue, name: listname }, function (result) {
// assuming the server returned json update the contents of the
// second selectbox
var listB = $('#' + listname).parent().parent().find('.ajaxlistC');
listB.empty();
$.each(result, function (index, item) {
listB.append(
$('<option/>', {
value: item.id,
text: item.name
})
);
});
});
});
}));
</script>
And the result: