Populate a DropDown/Select based on the value chosen on another DropDown - c#

I'm a beginner developer but I stumbled across a case I can't solve.
I'm using ASP.NET MVC with C# plus some javascript (JQuery, JSON...).
What I have to do is to populate a dropdown based on the value chosen in other.
It seems simple (and I know it is) but this particular case is eluding me.
I've lost many hours and I'm still bonking my head. If anyone can help I'd be very grateful.
My code is as follows:
I have an object of the class "Task" that have both a Phase and an Order. The Orders available to the user in the second dropdown will depend on the Phase this Task was assigned to in the firts dropdown. Order is merely an Int32 (order from ordering in a schedule, not from business order)
The First DropDown uses this IF to check if a session is null, then procedes to show a default message or bring a selected value as default.
<%
if (TempData["TaskObject"] != null)
{
var Phases = new SelectList(ViewData["phaseList"] as List<Phase>, "Phase_ID", "Phase_Name", ((Task)TempData["TaskObject"]).Phase_ID.ToString());
%>
<%=Html.DropDownList("Phase_ID", Phases, new { #class = "textbox"})%>
<%}%>
<%else
{%>
<%=Html.DropDownList("Phase_ID", (new SelectList((List<Phase>)ViewData["phaseList"], "Phase_ID", "Phase_Name")),
"Please Choose...",
new { #class = "textbox"})%>
<%} %>
The second DropDown is much like the first, but its SelectList is a list of lists. Each list contais the possible choices for each choice in the first DropDown. There won't be many, so don't worry about it.
<%if (TempData["TaskObject"] != null)
{
var orderList = (ViewData["orderList"] as List<List<int>>)[0];
var orders = new SelectList(orderList, ((Task)TempData["TaskObject"]).Phase_ID.ToString());
%>
<%=Html.DropDownList("Order_ID", orders, new { #class = "textbox"})%>
<%}%>
<%else
{%>
<%=Html.DropDownList("Order_ID", (new SelectList((List<int>)ViewData["phaseList"], "Phase_ID", "Phase_Name")),
"Please Choose...",
new { #class = "textbox"})%>
<%} %>
The question now is: how do I make the second DropDown change its values based on the selected value in the first DropDown ? I'm very poor at JavaScript (started studying though). We're using JQuery, JSON at the project.
Thanks in advance for your atention.

You basically want to attach a javascript event onto the first drop list and have jquery query a web service (or other) to get the details for that ID. Then in javascript you re-render the second drop list with the available options. A pretty good example is here. Javascript extract from the example is below:
$(function() {
$.getJSON("/Home/Countries/List", function(data) {
var items = "---------------------";
$.each(data, function(i, country) {
items += "" + country.Text + "";
});
$("#Countries").html(items);
});
$("#Countries").change(function() {
$.getJSON("/Home/States/List/" + $("#Countries > option:selected").attr("value"), function(data) {
var items = "---------------------";
$.each(data, function(i, state) {
items += "" + state.Text + "";
});
$("#States").html(items);
});
});
});

You need to catch the first DropDown's change event. and in this populate / select the value you needs.
$('#Phase_ID').change(function(){
var t = $(this);
$('#Order_ID').val(t.val()); // this is only for example.
});

There's a good tutorial on how to do that From Stephen Walther
it should be easy to do

Related

Validate dropdown item does not occur more than once in a list of dropdown fields with the same id

I have a form where the user can add as many rows as needed. Each time they are expected to select a different option from the dropdown list provided. At the moment there is no validation to stop them selecting the same value multiple times.
Each row is a "ResourceCount".
The ViewModel has an IList of ResourceCountViewModel, so each row is being added as an item to the list.
The ResourceCount view model consists of an "id" to store the dropdown value selected and a "quantity" for the number field.
I can't think of a way to use the Compare annotation in this scenario.
How can I implement appropriate validation for this?
EDIT:
There is lots of good advice in the accepted answer. I went with a simple check in the controller post action:
if (resourceCounts.Count != resourceCounts.Where(d => d.Id!= 0)
.Select(x => x.Id)
.Distinct()
.Count())
{
ModelState.AddModelError(string.Empty, "You can't select the same option more than once");
//etc.
}
This is simply not possible using a ValidationAttribute (either in-built or custom ones) and MVC's unobtrusive client side validation.
Validation attributes are applied to properties of a model (your class), and the context in which validation is checked is for that instance only - it has no knowledge of other instances of the model within the collection, therefore it cannot compare other instances.
Conversely if you apply a ValidationAttribute to a collection (e.g. List<T> property), unobtrusive validation will not work because the data-val-* attributes necessary to add rules to the $.validator could only be generated if you include an input for the collection property (as opposed to each property of each object in the collection) which means ModelBinding would fail.
You will need to write your own controller code and scripts to achieve your custom validation.
On the client side, you could handle the .change() event of the <select> and check if any previous selections match, and if so display an error message. You have not shown your model, or the view, but based on the following html (repeated for each object in the collection
<select class="select" .....>
<option value="">Please select</option>
<option value="1">On-call</option>
....
<select>
<div class="error"></div> // see notes below if you using ValidationMessageFor()
then the script would be
var errors = $('.error');
var selects = $('.select');
$('.select').change(function() {
var selected = $.map(selects, function(s, i) {
return $(s).val();
})
$.each(selects, function(i, s) {
var error = $(this).next('.error');
var val = $(this).val();
var index = i;
if ($(this).val()) {
var others = selected.filter(function(s, i) {
if (i != index) {
return s;
}
});
if (others.indexOf(val) > -1) {
error.text('Please make a unique selection');
} else {
error.text('');
}
} else {
error.text('');
}
})
})
Refer this fiddle for a working example.
Alternatively you could hide/show (or disable) options in each <select> to prevent the user making invalid selections in the first place, but that becomes more complex if your dynamically adding/deleting items, and/or when your view is editing existing data where the property already has a selected value (I'll leave that to you to ask a new question showing your attempt if you want to implement that).
On the server side, you can check for duplicate values, and if so, add a ModelState error and return the view, for example
var selected = new List<int>();
for (int i = 0 i < model.Count; i++)
{
if (selected.Contains(model[i].YourProperty))
{
ModelState.AddModelError("", "Please make a unique selection");
break;
}
else
{
selected.Add(model[i].YourProperty);
}
}
if (!ModelState.IsValid)
{
return View(model);
}
....
or using linq
if (model.Select(x => x.YourProperty).GroupBy(x => x).Any(g => g.Count() > 1))
{
ModelState.AddModelError("", "Please make a unique selection");
}
which would then be displayed in the views #Html.ValidationSummary().
If your using #Html.ValidationMessageFor(m => m[i].YourProperty) in your view for each dropdownlist, then the above loop can be modified to
if (selected.Contains(model[i].YourProperty))
{
var propertyName = string.Format("[{0}].yourPropertyName", i);
ModelState.AddModelError(propertyName, "Please make a unique selection");
break;
}
and modify the script to add/remove the message for the <span> element generated by ValidationMessageFor() (i.e instead of the <div class="error"> element as shown above)
As a side note, if you want to learn more about how validation attributes in conjunction with client side validation work, I recommend reading The Complete Guide To Validation In ASP.NET MVC 3 - Part 2.

How to detect if a check box is selected using MVC3 Razor

As I am new to MVC framework, I have been spending a couple of hours to generate a check box list in a View file. Finally, I could figure it out well. Here is my code:
#foreach (var item in Model.GetRoleNames)
{
#Html.CheckBox("chk_" + item.Value, new { value = item.Value })#item.Text<br />
}
But, I need to detect which of them is selected and if all the ckeckboxes are left unchecked, then preventing some operations.
Question: How can I get the checked items when I am within a controller action?
As the others said, you should use a Boolean value as the second parameter to CheckBox to indicate the checked status. A bit of string manipulation should help you get the ids of the selected check boxes..
First lets change the way the checkbox helper is used
<div id='myCheckboxDiv'>
#foreach (var item in Model.GetRoleNames)
{
#Html.CheckBox("chk_" + item.Value, false)#item.Text<br />
}
</div>
As you can see, I have set the second parameter to false and wrapped the mix in a div
And, when you want to get the ‘values’ associated with the selected checkboxes
var values = $(‘# myCheckboxDiv’).find('input:checkbox:checked').map(function () {
// get the name ..
var nameOfSelectedItem = this.attr('name');
// skip the ‘chk_’ part and give me the rest
return nameOfSelectedItem.substr(4);
}).get();
I am assuming item.Value to be a number. If its is not, please remove the white spaces using C#

Setting the Selected Value of a Dropdown list in the View from the Controller Action

I have 5 dropdowns, which are basically displaying "Select", "Yes" and "No". Initially they are set to "Select". Once he user chooses something, I am storing the data in a cookie (with Jquery) and eventually passing this to the ViewModel so that I can use it in the Controller.
When the user refreshes the page, I want these dropdown lists to be populated again with the value I have in the ViewModel.
At the moment I have the following code :-
Inside the View I have
<%: Html.DropDownList("FirstQuestYesNo", ViewData["FirstQuestYesNoData"] as SelectList, new { #class = "normalDropdowns" })%>
and in my controller I have the following :-
var ddlYesNoData = new SelectList(new[]
{
new {ID="",Name=#Resources.GeneralTerms.GeneralTerms_Select},
new {ID="Yes",Name=#Resources.GeneralTerms.GeneralTerms_Yes},
new{ID="No",Name=#Resources.GeneralTerms.GeneralTerms_No},
},
"ID", "Name", 1);
//Refresh the YesNo dropdown with the correct vals
Dictionary<string, string> YesNoData = new Dictionary<string, string>();
YesNoData.Add("FirstQuestYesNoData", viewModel.FirstQuestYesNoValue);
YesNoData.Add("SecondQuestYesNoData", viewModel.SecondQuestYesNoValue);
YesNoData.Add("ThirdQuestYesNoData", viewModel.ThirdQuestYesNoValue);
YesNoData.Add("FourthQuestYesNoData", viewModel.FourthQuestYesNoValue);
YesNoData.Add("FifthQuestYesNoData", viewModel.FifthQuestYesNoValue);
foreach (var item in YesNoData)
{
ViewData[item.Key] = ddlYesNoData;
if (item.Value != null)
{
var selected = ddlYesNoData.Where(x => x.Value == item.Value).First();
selected.Selected = true;
}
}
So basically what I am doing is get the value of each dropdown from the viewModel, and then try to set that value inside my View. As a result of what I am doing, I am getting all the DropdownLists option as "Select" instead of the value inside my viewModel.
The problem is that I do not know how to "target" the specific DropDownList. How can I target the DropDown (in this case "FirstQuestYesNo") from the Controller using my code?
Thanks for your help and time.
In your controller action simply set the FirstQuestYesNo property to the corresponding value. For example:
ViewData["FirstQuestYesNo"] = "Yes"; // this value might come from a cookie
This will automatically preselect the option with value="Yes". Obviously this value will come from the cookie. You don't need any foreach loops.

SelectedItem not being remembered in SelectList in ASPNET.MVC

I have the following code which is meant to populate a dropdown with a bunch of integer values and make the currently selected value (in this case, 13) be the selected item.
I've used the same technique but for string values and it works great, remembering each time when I get to the view what the current value is.
In controller:
var x = new[] { 1, 2,3,4,5,6,7,8,9,10,11,12,13,14,15 };
ViewData["Field"] = new SelectList(x, 13);
In view:
<%=Html.DropDownList("Field", (IEnumerable<SelectListItem>)ViewData["Field"])%>
When I debug and watch the ViewData["Field"] object, it does have a selectedValue of 13 and so it must be reaching the View but getting ignored there as all I see on the page is a dropdown with the values 1 to 15, but with 1 showing (none selected so shows the first one)
Is this a bug or am I doing something really stupid?
Thanks
Graeme
I seem to recall that it doesn't actually use the Selected property of the SelectList element. I usually have one ViewData item be the select list and another be the selected value.
Controller:
var x = new[] { 1, 2,3,4,5,6,7,8,9,10,11,12,13,14,15 };
ViewData["Fields"] = new SelectList(x);
ViewData["Field"] = 13;
View
<%= Html.DropDownList("Field", (IEnumerable<SelectListItem>)ViewData["Fields"] ) %>
This was happening to me! I was pulling my hair out for hours, but I eventually figured it out. In my case I was creating a drop-down list like this:
<%= Html.DropDownList("bookId", Model.ProductMenu, new { onchange = "goToBook();" })%>
And it was not printing the selected option. But the dropdown right next to it was working fine:
<%= Html.DropDownList("segmentIndex", Model.SegmentMenu, new { onchange = "goToSegment();" })%>
They were being generated the exact same way in the controller, and the debugger would always show the properly selected value as the view was returned. So what the heck?
The difference was in the view itself. "bookId" in my app happens to be a route/querystring value and segmentIndex is not. Simply changing the name "bookId" in the view to "bookIdBLAH" fixed it!

ASP.Net MVC Add Items To Bound Dropdownlist

My page view currently has a dropdownlist on it that is getting bound to a collection from the controller. This is working fine, However I want to insert an item to the top of the dropdownlist that is not in my collection e.g the list currently gets the following items
Open
Closed
I want to add a third option of "All" but I don't want to add this option to my database. In Webforms I would have just bound the control then inserted another item however it seems this is not possible with MVC, am I right in thinking I will need to add some Javascript to the view to add this new item once the dropdownlist has been bound?
Thanks
No. Construct your data as a list of SelectListItems and prepend in the controller.
var list = db.Table
.Select( t => new SelectListItem
{
Key = t.ID.ToString(),
Value = t.Name
} )
.ToList();
list.Insert( 0, new SelectListItem { Key = "-1", Value = "All" } );
ViewData["TableSelect"] = list;
On the view side:
<%= Html.DropDownList( "TableID",
(IEnumerable<SelectListItem>)ViewData["TableSelect"] ) %>
Simple
you can make it as you wish in controller.
and pass it in viewdata.
other option is directly in view page.
<%= Html.DropDownList("DropDown","all" )%>
But you can add only one option..
Make sure you are not storing added options in ur db, right?
so before you save it, check option value in action and apply your logic.
Newer implementation
var list = _db.Status.ToList();
list.Add(new Status(){DevelopmentStatusID = -1, DevelopmentStatusDesc = "All"});
var result = list.OrderBy(d => d.StatusID).ToList();
ViewBag.StatusID = new SelectList(result, "StatusID", "StatusDesc");
Then in the index.html
#Html.DropDownList("StatusID", null, htmlAttributes: new {#class = "form-control"})

Categories

Resources