I am very new to ASP.NET and I am using the MVC 3 framework of ASP.Net. I was trying to filter the options of a dropdown list using another drop down and I can't manage to do that. I was trying to do this first by populating both the list of main categories and and sub categories and loading them to the page.Then setting the class attribute of the options of each sub-category to their parent category. Finally on the click of the parent category from the first dropdown list only show the child sub-category and hide the rest(This is how i did it previously in java). But in ASP.Net MVC the html code is so different i can't even set the class attribute for each option of the dropdown it generally sets the class for all the drop downs not for each option. This is what I have right now
This is my View
<p>
@Html.LabelFor(model => model.CategoryId)
@Html.DropDownListFor(x => x.CategoryId , new SelectList(Model.Categories, "CategoryId", "CategoryName"), new { onchange= "this.form.submit();"})
</p>
<p>
@Html.LabelFor(model => model.SubCategories)
@Html.DropDownListFor(x => x.SubCategories, new SelectList(Model.SubCategories, "SubCategoryId", "SubCategoryName"), new { @class = "Category1.categoryname" })
</p>
This is my model
public class TestQuestionsViewModel
{
public string CategoryId { get; set; }
public IEnumerable<Category> Categories { get; set; }
public string SubCategoryId { get; set; }
public IEnumerable<SubCategory> SubCategories { get; set; }
}
This is my controller class method
public ActionResult Create()
{
var model = new TestQuestionsViewModel
{
Categories = resetDB.Categories.OrderBy(c => c.categoryid),
SubCategories = resetDB.SubCategories.OrderBy(sc => sc.subcategoryid)
};
return View(model);
}
My questions is How can i set the class attributes for each individual options. Or if anyone has a suggestion on how to do this in a different way I am open for any solution. Thank you.
Loading all the Sub Items to the page when the page loads initially, does not seems to be a good idea to me. What if you have 100 Categories and Each categories has 200 sub category items ? Do you really want to load 20000 items ?
I think you should do an incremental way of loading. Provide the Main Category dropdown with the values, Let the user selects one item from that. Make a call to the Server and get the Sub categories belongs to the selected category and load that data to the second dropdown. You can use jQuery ajax to do it so that user will not feel a complete page reload when he select one drop down. This is how i will do it.
Create the ViewModel which has both category properties
public class ProductViewModel
{
public int ProductId { set;get;}
public IEnumerable<SelectListItem> MainCategory { get; set; }
public string SelectedMainCatId { get; set; }
public IEnumerable<SelectListItem> SubCategory { get; set; }
public string SelectedSubCatId { get; set; }
}
Let your GET Action method returns this strongly typed view with the content for MainCategory filled
public ActionResult Edit()
{
var objProduct = new ProductViewModel();
objProduct.MainCategory = new[]
{
new SelectListItem { Value = "1", Text = "Perfume" },
new SelectListItem { Value = "2", Text = "Shoe" },
new SelectListItem { Value = "3", Text = "Shirt" }
};
objProduct.SubCategory = new[] { new SelectListItem { Value = "", Text = "" } };
return View(objProduct);
}
and in your strongly typed View,
@model MvcApplication1.Models.ProductViewModel
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
@using (Html.BeginForm())
{
@Html.DropDownListFor(x => x.SelectedMainCatId, new SelectList(Model.MainCategory,"Value","Text"), "Select Main..")
@Html.DropDownListFor(x => x.SelectedSubCatId, new SelectList(Model.SubCategory, "Value", "Text"), "Select Sub..")
<button type="submit">Save</button>
}
<script type="text/javascript">
$(function () {
$("#SelectedMainCatId").change(function () {
var val = $(this).val();
var subItems="";
$.getJSON("@Url.Action("GetSub","Product")", {id:val} ,function (data) {
$.each(data,function(index,item){
subItems+="<option value='"+item.Value+"'>"+item.Text+"</option>"
});
$("#SelectedSubCatId").html(subItems)
});
});
});
</script>
Add GetSub action method to your controller to return the sub categories for the selected category. We are returning the response as Json
public ActionResult GetSub(int id)
{
List<SelectListItem> items = new List<SelectListItem>();
items.Add(new SelectListItem() { Text = "Sub Item 1", Value = "1" });
items.Add(new SelectListItem() { Text = "Sub Item 2", Value = "8"});
// you may replace the above code with data reading from database based on the id
return Json(items, JsonRequestBehavior.AllowGet);
}
Now the selected values will be available in your HTTPOST Action method
[HttpPost]
public ActionResult Edit(ProductViewModel model)
{
// You have the selected values here in the model.
//model.SelectedMainCatId has value!
}
You need to add another method to handle the postback and filter the sub-category options. Something like this:
[HttpPost]
public ActionResult Create(TestQuestionsViewModel model)
{
model.SubCategories = resetDB.SubCategories
.Where(sc => sc.categoryid == model.SubCategoryId)
.OrderBy(sc => sc.subcategoryid);
return View(model);
}
Edit
Btw, if you still need to set the class name to the other drop-down, you can't do it like that. The easiest way would by to add a "SelectedCategoryName" property to your model, and reference like { @class = ModelSelectedCategoryName }.