Reputation: 15807
I am working with cascading dropdowns in MVC. It appears that I will not be able to easily create dropdowns on demand, instead I will have to add the dropdowns before sending it to the client.
This is how I am doing it right now:
In the aspx page
<%: Html.DropDownListFor(model => model.ModelViewAd.Category1, Model.ModelViewAd.Category1List, "-- Välj kategori --")%>
<%: Html.DropDownListFor(model => model.ModelViewAd.Category2, Model.ModelViewAd.Category2List, "-- Välj kategori --")%>
<%: Html.DropDownListFor(model => model.ModelViewAd.Category3, Model.ModelViewAd.Category3List, "-- Välj kategori --")%>
<%: Html.DropDownListFor(model => model.ModelViewAd.Category4, Model.ModelViewAd.Category4List, "-- Välj kategori --")%>
This is rendered like this :
<select id="ModelViewAd_Category1" name="ModelViewAd.Category1">
<option value="">-- Välj kategori --</option>
<option value="10">Fordon</option>
<option value="15">För hemmet</option>
<option value="17">Bostad</option>
</select>
<select id="ModelViewAd_Category2" name="ModelViewAd.Category2">
<option value="">-- Välj kategori --</option>
</select>
<select id="ModelViewAd_Category3" name="ModelViewAd.Category3">
<option value="">-- Välj kategori --</option>
</select>
<select id="ModelViewAd_Category4" name="ModelViewAd.Category4">
<option value="">-- Välj kategori --</option>
</select>
This is what the script on the page looks like:
<script type="text/javascript">
$(function () {
$("select#ModelViewAd_Category1").change(function () {
var id = $(this).val();
var urlAction = "/AdCategory/GetCategoriesByParent1/" + id;
$.getJSON(urlAction, { id: id }, function (data) {
$("#ModelViewAd_Category2").addItems(data.d);
});
});
$("select#ModelViewAd_Category2").change(function () {
var id = $(this).val();
var urlAction = "/AdCategory/GetCategoriesByParent1/" + id;
$.getJSON(urlAction, { id: id }, function (data) {
$("#ModelViewAd_Category3").addItems(data.d);
});
});
$("select#ModelViewAd_Category3").change(function () {
var id = $(this).val();
var urlAction = "/AdCategory/GetCategoriesByParent1/" + id;
$.getJSON(urlAction, { id: id }, function (data) {
$("#ModelViewAd_Category4").addItems(data.d);
});
});
});
</script>
And then I have an included file that contains this:
$.fn.clearSelect = function () {
return this.each(function () {
if (this.tagName == 'SELECT')
this.options.length = 0;
});
}
$.fn.addItems = function (data) {
return this.clearSelect().each(function () {
if (this.tagName == 'SELECT') {
var dropdownList = this;
$.each(data, function (index, optionData) {
var option = new Option(optionData.Text,
optionData.Value);
if ($.browser.msie) {
dropdownList.add(option);
}
else {
dropdownList.add(option, null);
}
if ($(this).children().size() < 2) {
$(this).hide();
}
else {
$(this).show();
}
});
}
});
}
The problem I now have is that I need to hide the dropdowns that do not contain any options or only contain one option. This should be checked when doing a call to the service as well as when the page is sent to the client ("POSTBACK").
What I need is :
Any suggestions on this?
Upvotes: 0
Views: 909
Reputation: 2077
I wrote a blog post about this here (minus the hiding part - which you seem to have nailed down). Essentially, you will need to rebuild the dropdown with the selected values if there is an error.
$("#ClientId").change(function () {
var clientId = "";
$("#ClientId option:selected").each(function () {
clientId += $(this)[0].value;
});
var url = '<%:Url.Action("ProjectList", "Client") %>' + "/" + clientId;
$.getJSON(url, null, function (data) {
var selectedValue = '<%:Model.ProjectId %>';
$("#ProjectId").empty();
$.each(data, function (index, optionData) {
if (optionData.OBJID == parseInt(selectedValue))
$("#ProjectId").append("<option value='" + optionData.ObjId+ "' selected='true'>" + optionData.Name + "</option>");
else
$("#ProjectId").append("<option value='" + optionData.ObjId + "'>" + optionData.Name + "</option>");
});
});
}).change();
Upvotes: 3
Reputation: 15807
I did not find any solution on the prevouse solution so I decided to try this : http://weblogs.asp.net/rajbk/archive/2010/05/20/cascadingdropdown-jquery-plugin-for-asp-net-mvc.aspx
The problem here is that I need to hide the dropdowns that are not selected and to acomplish this I have changed to this :
post: function () {
methods.showLoading();
$.isFunction(config.onLoading) && config.onLoading.call($this);
$.ajax({
url: actionPath,
type: 'POST',
dataType: 'json',
data: ((typeof config.postData == "function") ? config.postData() : config.postData) || 'id=' + $(source).val(),
success: function (data) {
methods.reset();
$.each(data, function () {
$this.append($(optionTag)
.attr("value", this.Value)
.text(this.Text));
});
if (hideEmpty == true) {
if ($this.children().size() < 2) {
$this.css("visibility", "hidden");
}
else {
$this.css("visibility", "visible");
}
}
methods.loaded();
$.isFunction(config.onLoaded) && config.onLoaded.call($this);
},
error: function () {
methods.showError();
}
});
}
};
As you can see, all I have added is the
if (hideEmpty == true) {
if ($this.children().size() < 2) {
$this.css("visibility", "hidden");
}
else {
$this.css("visibility", "visible");
}
}
The effect of this is that it will work grate untill the user posts a form that is not correct and the view is returned to the client. Then all but the first dropdown is hidden even when the other dropdowns is set?
I supose I will have to run some function when MVC sets the dropdown to check if it should be hidden or not, but how do I do this?
Upvotes: 0
Reputation: 22760
There is another way to do this using PartialViews.
If you create a partial view for each dropdown, or a generic one if you can, then you simply render the first one on load.
When you change the selection of a dropdown you do an ajax postback which does one of two things.
1) it checks to see if you have a selection in the dropdown. If you do thet\n it grabs data and does a return PartialView("PVName", PVModel);
This will return your partial view as fully rendered html.
2) if there is no selection then return an empty string or null;
Your jquery then simply replaces a div with the contents of the returned html. in the case of null you'd replace the dic with nothing which effectively removes the dropdown.
So you html might look like this;
<div class="firstdd"><dropdown/></div>
<div class="seconddd"></div>
on callback from the ajax call you simply $('.seconddd').html(returnedHTML);
i hope this makes sense and simplifies your code somewhat.
Upvotes: 0