How to initialize select2 that uses a query for data when I already have a value
-
21-12-2019 - |
質問
I have a view with 2 select boxes which are "cascading". A user selects a value from the first box and the second is populated based on the new value. This is done with Select2's query
option, and works fine on the first load of the page. However, when I post the page and then render it, both select boxes already have values (say A and 1), but the dependent checkbox is not initialized. I have done a few things with initSelection
and it didn't help much, sometimes just getting me into an loop.
What I am trying to do is this:
- Link the two boxes
- When the first box changes, reset the data in the second box and clear the value
- When the page is re-drawn, and a value has already been selected (e.g. response to POST)
- Go to server and get the data
- Show the correct value for the existing
<input type='hidden' value='xxx'>
- if that value exists in the list, of course
- if not, set value to blank (optionally fire jquery validation
- Searching/constant querying is not needed. Just load once on change
I am thinking about changing this entire, so if this is really the wrong way to go about this, I'd be happy to know.
// caches ajax result based on `data`
// if data has been requested before, retrieves from the cache (nothing special)
// based on other code that did it all inside the `query` function directly
var locationsCache = new AjaxCacheClassThing( {
url: '...',
data: function() { return { masterId: $('#ParentBox').val(); } }
});
$(function() {
$('#ParentBox').change(function () {
$('#ChildBox').select2('data', null);
});
$('#ChildBox').select2({
query: locationsCache.queryCallbackHandler,
selectOnBlur: true,
});
});
The HTML uses the standard MVC helpers, and the HTML is rendered just fine.
@Html.DropDownListFor(m => m.ParentBox, SelectListOfStuff) // standard <select>
@Html.HiddenFor(m => m.ChildBox)
Here is how this scenario goes:
ParentBox
is required (no empty option)- First Load: there is no value selected
- Open the
DependentBox
- Ajax query issues correctly
- Dropdown populates as expected
- Open the
- Second Load
- Master box selects value just fine
ChildBox
hidden input has value="xx" just fine- It does not show a selected item
- Clicking dropdown populates the box as expected (from cache)
解決
After some time spent, and lots of time on here and other places, I figured out how this all works (at least some parts of it!). Way simpler than I thought it was, but still surprised this isn't supported out of the box in some way. Seems like a really common request.
query
andajax
andinitselection
aren't that useful in this scenario- They query each time a the search box changes (not desired)
- They complicate everything
- You need to init the select2 manually
- If you use
{ data: ... }
then you don't needquery
orajax
- Set the "value" on your
hidden input
if you have one, so the item gets selected - You have to recreate the box when you get new data
- It is really simple. This is the simplest case, using no extra features or attributes
Javascript:
$(function() {
$('#ParentBox').change(createChildSelect2);
createChildSelect2();
});
function createChildSelect2() {
makeAjaxRequest( function( newData ) {
$('#ChildBox').select2( { data: newData } );
});
}
function makeAjaxRequest(callback) {
// calls a.jsp?parentId={?} and then the callback when done.
jQuery.ajax({
url: 'a.jsp', dataType: 'json',
data: function() {
return { parentId: $("#parentBox").val() };
}
})
.done(function (data) {
callback(data);
});
}
The HTML is all the same. A type=text
and type=hidden
both work:
<select id="ParentBox">
<option ... >
<option ... >
<select>
<input id="ChildBox" type="hidden" class="input-medium" value="1"/>
Or using Razor:
@Html.DropDownListFor(m => m.MasterBox, SelectListOfStuff) // standard <select>
@Html.HiddenFor(m => m.DependentBox)