I'm using Unify template which has jquery chosen library for select boxes. My html code is as follows:
<div>
<select class="select-evaluation-makes js-evaluation-custom-select u-select-v1 g-min-width-200 g-brd-none g-bg-secondary g-color-main g-color-primary--hover g-py-12"
required
data-placeholder="{% trans "Select brand" %}"
data-open-icon="fa fa-angle-down"
data-close-icon="fa fa-angle-up">
</select>
<select class="select-evaluation-models js-evaluation-custom-select u-select-v1 g-min-width-200 g-brd-none g-bg-secondary g-color-main g-color-primary--hover g-py-12"
required disabled
data-placeholder="{% trans "Seect model" %}"
data-open-icon="fa fa-angle-down"
data-close-icon="fa fa-angle-up">
</select>
<select class="select-evaluation-years js-evaluation-custom-select u-select-v1 g-min-width-200 g-brd-none g-bg-secondary g-color-main g-color-primary--hover g-py-12"
required disabled
data-placeholder="{% trans "Select year" %}"
data-open-icon="fa fa-angle-down"
data-close-icon="fa fa-angle-up">
</select>
</div>
And my JS is as follows:
<script>
const select_makes_selector = $(".select-evaluation-makes");
const select_models_selector = $(".select-evaluation-models");
const error_box = $("#error-box");
const error_message = $("#error-message");
$(document).ready(function () {
loadMakesOnPageLoad();
//Get models on make change
select_makes_selector.on('change', function (e, params) {
loadModels(parseInt(params["selected"]))
});
});
function loadMakesOnPageLoad() {
$.ajax({
type: "GET",
url: "/vehicle-evaluation/get-makes/",
beforeSend: function () {
},
success: function (result) {
let makes = result['makes'];
select_makes_selector.append("<option></option>");
_.forEach(makes, function (make) {
select_makes_selector.append("<option class=\"evaluation-make g-brd-none g-color-main g-color-white--hover g-color-white--active g-bg-primary--hover g-bg-primary--active\" value=\"" + make.id + "\">" + make.name + "</option>")
});
$.HSCore.components.HSSelect.init('.select-evaluation-makes');
},
error: function (response) {
error_box.removeClass("hidden");
error_message.html('<strong>' + gettext("Oh snap!") + '</strong>' + gettext("Something went wrong. Makes couldn't be fetched"))
}
});
}
function loadModels(make_id) {
$.ajax({
type: "GET",
url: "/vehicle-evaluation/get-models/" + make_id + '/',
beforeSend: function () {
},
success: function (result) {
let models = result['models'];
select_models_selector.attr('disabled', false).trigger("chosen:updated");
select_models_selector.append("<option></option>");
_.forEach(models, function (model) {
select_models_selector.append("<option class=\"evaluation-model g-brd-none g-color-main g-color-white--hover g-color-white--active g-bg-primary--hover g-bg-primary--active\" value=\"" + model.id + "\">" + model.name + "</option>")
});
$.HSCore.components.HSSelect.init('.select-evaluation-models');
},
error: function (response) {
error_box.removeClass("hidden");
error_message.html('<strong>' + gettext("Oh snap!") + '</strong>' + gettext("Something went wrong. Models couldn't be fetched"))
}
});
}
</script>
The problem is with the initialisation of those select boxes. They can be initialised only once if I get it right.
With my code I get:
Thus only the first one is initialised with $.HSCore.components.HSSelect.init('.select-evaluation-makes'); in loadMakesOnPageLoad function. But that is not what I want. All three need to be initialised.
If I change brands select box, then the models select box is also initialised. But If I change the brands select box again, then the model select box doesn't work and it isn't updated. It's probably because it hits $.HSCore.components.HSSelect.init('.select-evaluation-models'); again in ajax success call of loadModels function.
If I initialise them with common class as follows: $.HSCore.components.HSSelect.init('.js-evaluation-custom-select'); they are initialised:
But then onChange event on brands select box doesn't work. If the brands select box is changed then the models select box isn't updated, probably the same reason as above. It tries to initialise it again, this time with $.HSCore.components.HSSelect.init('.select-evaluation-models');
Any idea what is going on and how can I solve it? It drives me crazy.
After you updated the select with ajax response put on the next line:
$(".select-evaluation-makes").trigger("chosen:updated");
You must trigger "chosen:updated" event as per chosen docs show
Related
I need to create an enhanced transferbox, using HTML, JavaScript and JQuery.
I have a set of options a user can select from and associate with an attribute. The selection and deselection must be accomplished with two SELECT HTML elements (i.e., a transferbox). For example, these options can be a list of skill names.
When the 'add' button is clicked, the option(s) selected in the first SELECT element, along with an attribute (e.g. number of years from a text box) must be transferred from the source SELECT element to selected/destination SELECT element. The attribute must be displayed along with the item text in this second SELECT element (for example, the item displays the skill and the number of years).
When the 'remove' button is clicked, the selected option(s) in the second SELECT element must be moved back to the first SELECT element (in the original format .. without the attribute).
JSON should be the data format for initial selection setup and saving latest selections.
I want an initial set of selections and attributes to be set via JSON in an a hidden input field. I want the final set of selections to be saved to JSON in the same hidden input field.
Example HTML:
<input type="hidden" id="SelectionsId" value='[{ "id": "2", "attribute":"15"},{ "id": "4", "attribute":"3" }]' />
<!--<input type="hidden" id="SelectionsId" value='[]' />-->
<div>
<select class="MultiSelect" multiple="multiple" id="SelectFromId">
<option value="1">.NET</option>
<option value="2">C#</option>
<option value="3">SQL Server</option>
<option value="4">jQuery</option>
<option value="5">Oracle</option>
<option value="6">WPF</option>
</select>
<div style="float:left; margin-top:3%; padding:8px;">
<div>
<span>Years:</span>
<input id="YearsId" type="number" value="1" style="width:36px;" />
<button title="Add selected" id="includeBtnId">⇾</button>
</div>
<div style="text-align:center;margin-top:16%;">
<button title="Remove selected" id="removeBtnId">⇽</button>
</div>
</div>
<select class="MultiSelect" multiple="multiple" id="SelectToId"></select>
</div>
<div style="clear:both;"></div>
<div style="margin-top:40px;margin-left:200px;">
<button onclick="SaveFinalSelections();">Save</button>
</div>
Example CSS:
<style>
.MultiSelect {
width: 200px;
height: 200px;
float: left;
}
</style>
Visual of requirement:
Here's a solution to the challenge. The variables being setup at the start make this solution easy to configure and maintain.
When the page gets displayed, the SetupInitialSelections method looks at the JSON data in the hidden input field and populates the selected items.
When the 'Save' button clicked, the current selections are converted to JSON and placed back in the hidden input field.
Invisible character \u200C is introduced to delimit the item text and the attribute during display. This comes in to use if the item has to be removed and the original item text has to be determined so it can be placed back in the source SELECT element.
The selectNewItem variable can be set to true if you would like the newly added item to be selected soon after adding it to the SELECT element via the 'add' or 'remove' operations.
This solution supports multiple item selections. So multiple items can be added at once ... and similarly multiple items can be removed at once.
<script src="jquery-1.12.4.js"></script>
<script>
var savedSelectionsId = 'SelectionsId';
var fromElementId = 'SelectFromId';
var toElementId = 'SelectToId';
var includeButtonId = 'includeBtnId';
var removeButtonId = 'removeBtnId';
var extraElementId = 'YearsId';
var extraPrefix = " (";
var extraSuffix = " years)";
var noItemsToIncludeMessage = 'Select item(s) to include.';
var noItemsToRemoveMessage = 'Select item(s) to remove.';
var selectNewItem = false;
var hiddenSeparator = '\u200C'; // invisible seperator character
$(document).ready(function () {
SetupInitialSelections();
//when button clicked, include selected item(s)
$("#" + includeButtonId).click(function (e) {
var selectedOpts = $('#' + fromElementId + ' option:selected');
if (selectedOpts.length == 0) {
alert(noItemsToIncludeMessage);
e.preventDefault();
return;
}
var attribute = $("#" + extraElementId).val();
selectedOpts.each(function () {
var newItem = $('<option>', { value: $(this).val(), text: $(this).text() + hiddenSeparator + extraPrefix + attribute + extraSuffix });
$('#' + toElementId).append(newItem);
if (selectNewItem) {
newItem.prop('selected', true);
}
});
$(selectedOpts).remove();
e.preventDefault();
});
//when button clicked, remove selected item(s)
$("#" + removeButtonId).click(function (e) {
var selectedOpts = $('#' + toElementId + ' option:selected');
if (selectedOpts.length == 0) {
alert(noItemsToRemoveMessage);
e.preventDefault();
return;
}
selectedOpts.each(function () {
var textComponents = $(this).text().split(hiddenSeparator);
var textOnly = textComponents[0];
var newItem = $('<option>', { value: $(this).val(), text: textOnly });
$('#' + fromElementId).append(newItem);
if (selectNewItem) {
newItem.prop('selected', true);
}
});
$(selectedOpts).remove();
e.preventDefault();
});
});
// Setup/load initial selections
function SetupInitialSelections() {
var data = jQuery.parseJSON($("#" + savedSelectionsId).val());
$.each(data, function (id, item) {
var sourceItem = $("#" + fromElementId + " option[value='" + item.id + "']");
var newText = sourceItem.text() + hiddenSeparator + extraPrefix + item.attribute + extraSuffix;
$("#" + toElementId).append($("<option>", { value: sourceItem.val(), text: newText }));
sourceItem.remove();
});
}
// Save final selections
function SaveFinalSelections() {
var selectedItems = $("#" + toElementId + " option");
var values = $.map(selectedItems, function (option) {
var textComponents = option.text.split(hiddenSeparator);
var attribute = textComponents[1].substring(extraPrefix.length);
var attribute = attribute.substring(0, attribute.length - extraSuffix.length);
return '{"id":"' + option.value + '","attribute":"' + attribute + '"}';
});
$("#" + savedSelectionsId).val("[" + values + "]");
}
</script>
Iam trying to do autocomplete input box. Datalist rows are from JSON. I want that user sees name of the city (data[i].stationName below) while making his choise, but i would like to get that data[i].stationShortCode as a return attribute instead of name when city is selected.
Is that possible to do that way without that user needs to see that shortcode?
I tried to put those in array, but iam not figured out how that would help me or..
My js below:
$(document).ready(function(){
var url="https://rata.digitraffic.fi/api/v1/metadata/stations";
var stations=[];
var elem;
$.getJSON(url,function(data,status){
if(status=="success"){
$.each(data, function(i, item){
if(data[i].passengerTraffic!=false){
elem=$("<option value="+data[i].stationName+ ">");
elem.appendTo('#stations');
//stations[i]={value: data[i].stationName, data:data[i].stationShortCode};
}
else{
}
})
}
else{
console.log("Something went wrong");
}
})
});
And html:
<div class="stationSearch">
<input type="text" list="stations" id="station" placeholder="Valitse Asema"/>
<datalist id="stations"></datalist>
<button class="pick">Paina</button>
The idea of an array is OK, but it better be an object (or Map) so that you have direct access:
var stations = {};
// ...
$("<option>").attr("value", data[i].stationName).appendTo('#stations');
stations[data[i].stationName] = data[i].stationShortCode;
Now when you have the input value in an event handler (e.g. after button click), then get the short code from the input value like this:
var selectedShortCode = stations[$("#station").val()];
Here is working snippet:
var url="https://rata.digitraffic.fi/api/v1/metadata/stations";
var stations = {};
$.getJSON(url, function(data,status) {
if (status=="success"){
$.each(data, function(i, item){
if(item.passengerTraffic){
$("<option>").attr("value", item.stationName).appendTo('#stations');
stations[item.stationName] = item.stationShortCode;
}
});
}
else{
console.log("Something went wrong");
}
});
// ...
$("#station").on("input", function () {
$("#code").text(stations[$(this).val()]);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" list="stations" id="station" placeholder="Valitse Asema"/>
<datalist id="stations">
<option value="shortcode">longcode</option>
</datalist>
Code: <span id="code"></span>
Yes, modify your script where you build the <option> elements as such:
if(data[i].passengerTraffic!=false){
elem=$("<option value=" + data[i].stationShortCode + ">" + data[i].stationName + "</option>");
elem.appendTo('#stations');
}
This will generate <option> elements where the "stationShortCode" is the option value and the "stationName" is the displayed value.
So, I have two drodpowns, both dropdowns are working as expected. So, entry in second dropdowns determined by the entry selected in first drodpown. Also, I have added a script call CountrySelectionChanged on the page reload too so that second dropdown gets populated as per the intitial value of first dropdown.
<script type="text/javascript">
$(function () {
CountrySelectionChanged();
});
</script>
<div id="Admin">
Select an account:
#Html.DropDownList("countrySelection", (List<SelectListItem>)ViewBag.AvailableAccounts, new { onchange = "CountrySelectionChanged()"})
<p id="Temp">
Select a city:
<select id="City" name="City"></select>
</p>
</div>
AJAX CALL:
function CountrySelectionChanged() {
// logic taken out for brevity
$.ajax({
type: 'POST',
url: '/Settings/GetCity',
data: { accountId: accountId },
success: function (data) {
debugger;
var locationDropdown = '';
for (var x = 0; x < data.length; x++) {
locationDropdown += '<option value="' + data[x].Value + '">' + data[x].Text + '</option>';
}
$('#City').html(locationDropdown);
},
error: function () {
DisplayError('Failed to load the data.');
}
});
}
Question: Is there a way that I can use HTML Helper to display second dropdown too? Can I somehow inject the ajax return to a HTML Helper (Even if it's not strongly bound).
I have used a Bootstrap dialog box to get a file input, where the user first selects the type and then selects the file - I want to limit the files by extension with regard to the type selected.
Bootstrap dialog is built by a string and I was thinking of adding an onchange event to the selector as in the following, which I hoped would update the extension in accept in file input - but it gives an error setType is not defined.
How can I correctly dynamically capture the selected type and set it in the accept in the input where the HTML is built from string?
JSFiddle
var HTMLmessage = 'Type: <select onchange="setType(this)"> ..Option list </select> <br> <input type="file" accept=' + getType() + '>';
You can simply use jQuery for this. and use on(change) event of jQuery.
Here is the FIDDLE.
Piece of code
$(document).on("change", '#load-file-type', function(event) {
getType = $(this).find('option:selected').attr('data-ext');
$('#load-file').attr('accept',getType); // simply using this you can set it in the `accept` in file input.
});
Which allow you to trigger event on change.
you need event delegation https://jsfiddle.net/0c3d0885/1/ . As you are modifing/adding element after DOMload
document.getElementById('load-file-type').onchange = function setType(op) {
console.log(op);
getType = op.dataset.dataExt;
}
You could use event bubbling to be able to capture elements that are created at runtime. Similar to jQuerys event delegation.
Here is what you could do.
var optionList = [{
name: "XML",
id: "xmlVAL",
extension: ".xml"
}, {
name: "JSON",
id: "jsonVAL",
extension: ".json"
}, {
name: "CSV",
id: "csvVAL",
extension: ".csv"
}];
var typeOptions = (function(arr) {
var str = "";
arr.map(function(type) {
var op = "<option value=" + type.id + " data-ext=" + type.extension + " >" + type.name + "</option>";
str += op;
});
return str;
})(optionList);
var getType = ".xml";
function setType(op) {
// console.log(op);
getType = op.dataset.dataExt;
}
var message = ' Type: <select id="load-file-type" >' + typeOptions + ' </select> <br> File: <input id="load-file" type="file" style="display:inline" accept=' + getType + ' >'
document.getElementById("result").addEventListener("change", function(event) {
var target = event.target;
if (target.tagName.toLowerCase() !== "select") {
return;
};
console.log(target.options[target.selectedIndex].dataset.ext);
});
document.getElementById("result").innerHTML = message;
<div id="result">
</div>
I have three dropdownlists.
$(document).ready(function () {
$("#DropDownList1").change(function () {
$("#Id1").val($(this).val());
$("#Name1").val($("#DropDownList1 option:selected").text());
$('#Div1').load('/Account/Dropdown2/?Id1=' + $("#Id1").val());
});
$("#DropDownList2").change(function () {
$("#routeId").val($(this).val());
$("#routeName").val($("#RouteDropDownList option:selected").text());
$('#Div2').load('/Account/Dropdown3/?Id2=' + $("#routeId").val());
});
$("#DropDownList3").change(function () {
$("#Id3").val($(this).val());
$("#Name3").val($("#DropDownList3 option:selected").text());
});
});
In this DropDownList2 and DropDownList3 are added dynamicly.The problem is the dynamicly added dropdowns are not got registered in the page .So I am not getting its selected value from the onchange event.I added these controls as partial view.
Controller.
public ActionResult DropDownList2 (string Id1)
{
List<Emp> empList = new List<Emp>();
Emp em= new Emp ()
{
Id = "1",
Name = "Doac"
};
empList .Add(em);
ViewBag.DropDownList2= new SelectList(empList , "Id", "Name");
return PartialView();
}
Generated Html
<script type="text/javascript">
$('#CreateSubscriber').removeClass('menuHolderli').addClass('selectedMenu');
$(document).ready(function () {
$("#DropDownList").change(function () {
$("#Organization_Id").val($(this).val());
$("#Organization_Name").val($("#DropDownList option:selected").text());
$('#routeDiv').load('/Account/RouteDropdown/?organizationId=' + $("#Organization_Id").val());
});
$(document).on('change', "#RouteDropDownList", function () {
alert("hi");
$("#routeId").val($(this).val());
$("#routeName").val($("#RouteDropDownList option:selected").text());
$('#locationDiv').load('/Account/LocationDropdown/?routeId=' + $("#routeId").val());
});
$("#LocationDropDownList").change(function () {
$("#locationId").val($(this).val());
$("#locationName").val($("#LocationDropDownList option:selected").text());
});
});
</script>
<p class="message-info">
Passwords are required to be a minimum of 6 characters in length.
</p>
<script src="/Scripts/jquery.validate.min.js"></script>
<script src="/Scripts/jquery.validate.unobtrusive.min.js"></script>
<form action="/Account/Register" method="post"> <fieldset>
<legend>Registration Form</legend>
<ol>
<li>
<label for="Organization_Name">Name</label>
<input id="Organization_Id" name="Organization.Id" type="hidden" value="" />
<input id="Organization_Name" name="Organization.Name" type="hidden" value="" />
<select id="DropDownList" name="DropDownList"><option value="">---Select---</option>
<option value="516c0a18c891870f107aa74a">Choice School</option>
<option value="516d277bc8918701a44c131e">New Org</option>
<option value="516d1f492e6bba07dc245cc7">Olive</option>
</select>
<span class="field-validation-valid" data-valmsg-for="Organization.Name" data-valmsg-replace="true"></span>
</li>
</ol>
<div id="routeDiv"></div>
<div id="locationDiv"></div>
Use jQuery .on()
$(document).on('change', "#DropDownList2", function(){your code})
Repeat for your dropdown 3
Since, DropDownList2 and DropDownList3 are added dynamicly, you need to do this:
$(document).on('change', '#DropDownList1', (function () {
$("#Id1").val($(this).val());
$("#Name1").val($("#DropDownList1 option:selected").text());
$('#Div1').load('/Account/Dropdown2/?Id1=' + $("#Id1").val());
});
Similarly call other dyanmically added dropdowns also.
If you are adding the select options dynamically, why not use AJAX within AJAX?
$(function() {
$('#DropDownList').each(function () {
var dropdown = $(this);
dropdown.change(function() {
$.ajax({
url: 'Account/GetDropDownOptions',
type: 'GET',
data: {dropdownID: dropdown.attr('id'), value: dropdown.val()},
dataType: 'html',
cache: false,
success: function (data) {
var dropdown2 = $('#DropDownList2');
dropdown2.html(data);
dropdown2.change(function() {
$.ajax({
url: 'Account/GetDropDownOptions',
type: 'GET',
data: {dropdownID: dropdown2.attr('id'), value: dropdown2.val()},
dataType: 'html',
cache: false,
success: function (data) {
var dropdown3 = $('#DropDownList3');
dropdown3.html(data);
dropdown3.change(function() {
//....same thing as above pretty much
});
}
});
});
}
});
});
});
});
Then your controller action, GetDropDownOptions, would examine the DDL ID and selected value, understand what options it needed, then return the options as HTML. Or as a more elegant solution, you could have it return an object as json ( return Json(object) ) and then programatically create the elements in your javascript. You'd have to switch the dataType in the $.ajax to 'json'.
This way you have the dropdown change event after it has loaded the options. This change event loads DropDownList2's options and change event, which will load DDL3's options.
Haven't tested the code, but this idea will work. This sample assumes you already have the first DDL options loaded, but it seems you'll have to have add another layer of ajax to load those in as well. It also assumes the and DDL3 are already on the DOM at page load. You could add them to the DOM in your html to get this example to work, or change the IDs in the javascript to some container.