Kendo UI drop down; Initially has no values (only null) - asp.net-mvc

I am using ASP.NET MVC3, Jquery, and Kendo UI MVC Wrappers.
I have a simple Kendo UI drop down. It is a nullable drop down so I have the .OptionLabel property set to " ".
There are 2 scenarios when I load the page:
1.) The data for the drop down is supplied by the controller.
2.) The data for the drop down is not supplied by the controller in which case I am giving it an empty list
Upon the initial load of the page, the only available selection is the nullable option. The user can add more selections to the drop down by using other controls on the page.
When scenario #2 occurs, everything works perfectly fine. I get a drop down list with all of the selections and the null option. The items in the list come via my controller. The drop down works as expected.
When scenario #1 occurs. It seems like the drop down is not initializing or something like that. In this scenario I am sending an empty list from the controller. My expectation is that the drop down should have one selection which is the null option (because of my optionlabel), but instead I get a drop down that is in some sort of disabled state.
So in this situation, is passing an empty list to the drop down the right thing to do or should I be doing something else?
Here is the drop down declaration:
#(Html.Kendo().DropDownList()
.Name("allPeople")
.DataValueField("Id")
.DataTextField("Name")
.OptionLabel(" ")
.DataSource(source =>
{
source.Read(read =>
{
read.Action("_SelectPeopleList", "People");
}).ServerFiltering(true);
})
.Events(e => e
.Change("all_change").Open("all_open"))
)
So just to reiterate, when I hit scenario #2, _SelectPeopleList is returning a list and everything works fine.
When I hit scenario #1, _SelectPeopleList is returning an empty list and the drop down gets in something similar to a disabled state.
Hopefully I was clear enough.

OK, I just discovered a way to do this.
Instead of passing an empty list, I pass a list with id = 0 and and "" as the text field.
And then remove .OptionLabel(" ")
But then, if I have to do it this way, what is the point of having .OptionLabel??

Related

Pre-populate ListBox / MultiSelectList with selected items

Is there a way to pre-populate a MultiSelectList with selected items?
Example:
I have a single View that has the following ListBoxFor that will cause the page to update what it's displaying by allowing filtering of Model.Companies.
#Html.ListBoxFor(m => m.SelectedCompanies, new MultiSelectList(Model.Companies, "IdString", "CompanyName")
What I'd like to have happen is after the update, the MultiSelectList will have the items that were selected before the page updated and refreshed. Does that mean I need to return SelectedCompanies with what was selected, or is there another way?
I am using the javascript library Chosen for usability of the ListBox on the client side, but I don't think that this affects what I'm trying to do.
Sometimes, JS libaries can interfere with your desired results. I can't speak for Chosen JS library, but inspect the markup and see how it renders. As long as it still has the listbox on the client (it must have some input element defined somewhere; my guess it hides it and updates the values as they are selected), then yes it should integrate fine.
However, when the controller posts back, you have to repopulate the Model.SelectedCompanies property with whatever values came back from the POST operation to the controller. The property should still have the selected companies if you return a View from the POST operation. If you are using a RedirectToAction instead, you'd have to store the selections in TempData.

ViewModel not keeping data on postback

I have a ListBox implemented as below.
#if (Model.SelectListVendorBranchSearched != null )
{
#Html.ListBoxFor(model => model.SelectedVendorBranchLeft, Model.SelectListVendorBranchSearched, new {#class="listbox", #size ="10" })
}
But when the form is posted back the viewModel object does not have the original Data Source that the list was bound to. But it has the selected items posted back.
Is that the right behavior?
Let me try to explain what I am trying to achive.
I am trying to implement the following in ASP.NET MVC.
I have a search functionality that populates a list box say List box A. Now I need to select some items in the List Box A and move the items to another List Box say List Box B. Then do another search that refreshes the List Box A with fresh results. Then again select some more items in the List Box A and append to the items already in List Box B. In the end get the items in the List Box B and save it to DB. How can I do this without any JavaScript?

Why is CascadeFrom() not doing anything?

I'm really new to Kendo UI, and I'm having problems with CascadeFrom() not calling an action on my controller. Here's the bare bones of my problem:
// The parent dropdown
<select id="Testing">
<option value="0">Vehicle</option>
<option value="1">Driver</option>
<option value="2">Trailer</option>
</select>
// The dynamic dropdown
#(Html.Kendo().DropDownListFor(m => m.VDTId)
.DataValueField("Id")
.DataTextField("Item")
.DataSource(ds =>
{
ds.Read(c => c.Action("GetVDT", "CompanyVDTUnavailability")
.Data("getVDTSelection"))
.ServerFiltering(true);
})
.CascadeFrom("Testing"))
// Function to allow Kendo to pass a value to
// the type parameter of my GetVDT action.
function getVDTSelection() {
return {
type: parseInt($("#Testing").val())
};
}
The action is being called when the page first loads, and returns the correct data. The problem is, if I then make a selection from the Testing dropdown, the action is never invoked on the controller (I've verified this using a breakpoint on the action), meaning the dynamic dropdown never gets updated.
Looking through the official example, and other questions around SO, I can't see what I'm doing wrong. Could someone point me in the right direction, please?
Edit: I've tried Petur's solution below by changing the parent dropdown to the following:
#(Html.Kendo().DropDownListFor(m => m.Type)
.Name("Testing")
.DataValueField("Id")
.DataTextField("Text")
.BindTo(Model.UnavailabilityTypes))
This binds the parent dropdown correctly, but no longer invokes the controller action for the cascading dropdown even when the page first loads. Any suggestions?
Controller action signature as requested:
public JsonResult GetVDT(CompanyUnavailabilityType type)
Where CompanyUnavailabilityType is an enum.
Kendo DropDownList can cascade only from another Kendo DropDownList/ComboBox. Turn the first widget into kendo DropDownList and it should start working properly.
I think the problem is that getVDTSelection() is returning an int or string value not an Enum value. Change your method sig to an int if not, try a string and the method described in my comment
public JsonResult GetVDT(int type)
{
//AllowGet might be needed as well
return Json(jsonObjx,JsonRequestBehavior.AllowGet);
}
Edit:
You can also try to Manually force the ddl to cascade. Ditch CascadeFrom and do it manually.
function OnChangeOfParentDDL(e){
var parentValue = $("#ParentDDL").val();
$("#ChildDDL").val("").data("kendoDropDownList").text("");//clear it out
var child = $("#ChildDDL").data("kendoDropDownList");
child.dataSource.read({ type : parentValue });
}
Both Petur and C Sharper were on the right track with the problem.
I did need to build the dropdown using Html.Kendo.DropDownList() (I've just verified this after getting the solution to work.)
The method signature on the controller was a problem, but only because I'd had old testing methods left on there, leading to an ambiguous call.
The major difficulty for me was that nothing was being reported in the debugger, so diagnosing the problem was a pain. In the end, I used the Network tab of the Firefox web developer tools to ensure the Ajax request was indeed being sent, and it was. Inspecting that request showed it was leading to an ambiguous call on the controller.
Also, to clear up comments from C Sharper's answer:
The parseInt() call is not required.
The call will correctly map to an enum on the server-side, meaning the method signature I posted in my question is correct.

MVC PlaceHolder for DDL that disappears**

I've seen so many posts and examples of people using a DDL placeholder like this...
#Html.DropDownList("lstUsers",(SelectList)ViewBag.UsersList, "--Select User--")
or
#Html.DropDownListFor(u => u.RoleID, Model.RoleList, "Select", new { #id="hi"})
I mean yea these work, but I want the placeholder to disappear after the ddl index changed, and all these do is place dummy text for the 1st index which can then be selected again.
I haven't been able to find an answer for the life of me. I've tried jquery
$("#tb2").attr("placeholder", "--Please Select--"
which works for a textbox, but not a DropDown. I'm using dynamically generated ddl's
Thanks!
That's not how the select element works. That "placeholder" is actually a full-fledged option in the select list. It's value is usually set to an empty string so that if it's still selected on POST, an empty string is posted and will caused an error if the field is expected to have a value. It doesn't just disappear automatically on it's own.
A textbox is entirely different. When placeholder text is placed inside a textbox, it is literally overwritten by user input, hence why it goes away. In HTML5 textboxes now have an actual placeholder attribute, which will show and hide a bit of text based on the focus of the input. The select element has no equivalent, though.
You could potentially do what you want with some additional JavaScript. You would just watch for a change event on the select and if it has a value (not the "placeholder"), then you could remove the first item from the select (which should be the placeholder):
$('#mySelect').on('change', function () {
if ($(this).val() != '') {
var firstChild = $(this).children().eq(0);
if (firstChild.prop('value') == '') firstChild.remove();
}
});
(I'm using jQuery here because doing the same in straight JavaScript would be much more arduous and since you're using ASP.NET MVC, it's a safe bet you're also using jQuery)

MVC Dropdown lists bound depending on the value of another dropdown list

I am trying to write an MVC webpage that has two drop down lists. The content of the second list depends on what is selected in the first.
There does not seem to be a definitive way of doing this using built in MVC functions so I am going to have to roll my own. However I am not clear on the best way of getting all the functionality I require... which is "be the same as webforms" :)
I have created the dropdowns in a way similar to this
However I am not sure how to develop this so that if there is a 'selected' element in the first list when it is first bound this will flow through to automatically binding the second list on page load.
Edit:
Just to be clear I have the ability to bind the filtered list to the second dropdown. However if my Model contains a selection for the first dropdown the selection is set correctly but the second dropdown list does not fill.
(do I have to state I am newish to MVC and Javascript is like some alien language to me?)
Edit2:
I have thought about this a bit more.
Clearly I am strongly influenced by my time developing webforms and I don't quite 'get' MVC yet.
I think that really I have some things I should be catching in my model (ie if I already have the info to set the two dropdowns then I should in some way catch that in the controller and build the dropdowns pre set. Rather than trying to build an "ondatabound" type method and have the view call that (which was my initial intent)... Now I need to go and work out how to do that :)
This is one of the better implementations that I found. The question has also been discussed here.
You task contains 3 subtasks:
You should ajax get list of items for second ddl on changing selection of first ddl by using selected value
You should process action of getting list of items for 2-nd ddl by your Controller and return View with defined content of second ddl
You should update content of second ddl by getting result of processed action
<script type="text/javascript">
$(function(){
$("form #ddl_1").change(function(){
$.get({ // get request
url: "#Url.Action("MyController", "GetList"})" + "/" + $(this).val,
success: function(data){ // updating
$("form #ddl_2").html(data);
}
})
});
</script>
"GetList" action should take parameter "id" if you use default routes table (or you need to create special record at routes table with custom) and return partial view (without master page) with list of options for your ddl2, like this:
<option value="1">First</option>
<option selected value="2">Second</option>
<option value="3">Third</option>
See this blog post for creating cascading dropdown lists in asp.net mvc with downloadable source code.

Resources