Closed frellan closed 7 years ago
You create parent dropdown for Improvement.ImprovementArea
property and in cascading dropdown you specify that Improvement.ImprovementAreaId
should trigger the data loading. Because of that cascading dropdown is newer filled with data.
In addition to that dropdowns could be mapped only to simple properties (string, int and etc) and not to a complex objects because by the end of the day the value that is sent to server it is a value of selected
In your case, patent dropdown values will be Id
s of objects from dbAreas set
and dropdown name will be Improvement_ImprovementArea. When you post the form, default model binder will try to map this value to Model.Improvement.ImprovementArea property( ImprovementArea property of object that is stored as Improvement property of your model). So your model should look like this:
Improvement
ImprovementArea
If ImprovementArea
is a complex object, it will not work. If it is a simple type (such as string/int/long...) it will.
Instead of creating dropdowns for navigation properties you should create them for their Ids.
Parent dropdown is crated for ImprovementAreaId
and second dropdown for ImprovementSubAreaId
:
<div class="form-group">
@Html.LabelFor(m => m.Improvement.ImprovementAreaId)
@Html.DropDownListFor(m => m.Improvement.ImprovementAreaId,
Model.Areas, "Select area", new { @class = "form-control" })
</div>
<div class="form-group">
@Html.LabelFor(m => m.Improvement.ImprovementSubAreaId)
@Html.CascadingDropDownListFor(
expression: m => m.Improvement.ImprovementSubAreaId,
triggeredByProperty: m => m.Improvement.ImprovementAreaId,
url: Url.Action("GetSubAreas", "Improvements"),
ajaxActionParamName: "areaId",
optionLabel: "Select subarea",
disabledWhenParrentNotSelected: true,
htmlAttributes: new { @class = "form-control" })
</div>
I also don't understand what the ajaxActionParamName refers to exactly?
It is the name of an argument of an action on the server that you use to get the data for the cascading drop down. In your code you use it correctly. You set ajaxActionParamName: "areaId"
and the action on the server is public JsonResult GetSubAreas(int areaId)
Thank you for quick answer!
It all makes sense now but it still doens't work, nothing happens. I also get an error when I first load the page that the javascript code cant access a null value. It seems that it tries to add an observer to a null value. Do I have to instantiate the Model in the New action somehow?
Controller
var viewModel = new NewImprovementViewModel
{
Improvement = new Improvement(), // Do i really need to set the Area too?
Areas = dbAreas.Select(a => new SelectListItem { Text = a.Name, Value = a.Id.ToString() }).ToList()
};
return View(viewModel);
EDIT: It seems its trying to find an object with id ImprovementAreaId but it is actually _ImprovementImprovementAreaId, is this a bug?
I guess I can solve it by using simple attributes in the view model but chaining like this should work right?
Add 2 properties to your view model SelectedAreaId and SelectedSubAreaId:
public class NewImprovementViewModel
{
public int SelectedAreaId {get;set;}
public int SelectedSubAreaId{get;set;}
}
Create a dropdowns like this:
<div class="form-group">
@Html.LabelFor(m => m.Improvement.ImprovementAreaId)
@Html.DropDownListFor(m => m.SelectedAreaId,
Model.Areas, "Select area", new { @class = "form-control" })
</div>
<div class="form-group">
@Html.LabelFor(m => m.Improvement.ImprovementSubAreaId)
@Html.CascadingDropDownListFor(
expression: m => m.SelectedSubAreaId,
triggeredByProperty: m => m.SelectedAreaId,
url: Url.Action("GetSubAreas", "Improvements"),
ajaxActionParamName: "areaId",
optionLabel: "Select subarea",
disabledWhenParrentNotSelected: true,
htmlAttributes: new { @class = "form-control" })
</div>
Your post action should get the same NewImprovementViewModel ans an argument:
[HttpPost]
public ActionResult New(NewImprovementViewModel model)
{
//model.SelectedSubAreaId will have an id of selected sub-area
//model.SelectedAreaId will have an id of selected area
}
Yeah I did that, solved my problem. Thank you so much for your help!
Only thing that bugs me now is that the default "select subarea" can also be selected, is there a way to disable that option, or leave it out completely?
Thank you again.
"select subarea" is an option label and on not an option. You can modify it by setting optionLabel
parameter of the CascadingDropDownListFor helper. In order to leave it empty simply pass an empty string:
optionLabel: string.Empty,
I would also suggest you to add [Required] data annotation to the model properties to insure that user selects something:
public class NewImprovementViewModel
{
[Required]
public int SelectedAreaId {get;set;}
[Required]
public int SelectedSubAreaId{get;set;}
}
Don't forget this give us a star if you find this library useful
I'm trying to use this library with Entity framework model binding but I can't get the cascading dropdown to respond when I am selecting anything from the parent one, it's always disabled.
Controller.cs
New.cshtml
ViewModel
The other models have navigation properties tied to them so thats what I'm trying to set but it doesn't seem to work. Do I have to just use simple string properties in the view model like in the example and then bind everything in the POST request to the controller or is there a nice way to do this?
I also don't understand what the ajaxActionParamName refers to exactly?