Best way to populate select list with JQuery / Json? - javascript

Currently our dev team uses this pattern, but I can't help but wonder if there is a faster or more html-efficient way of accomplishing the same task.
HTML
<select id="myList" style="width: 400px;">
</select>
<script id="myListTemplate" type="text/x-jQuery-tmpl">
<option value="${idField}">${name}</option>
</script>
And this is the Javascript:
function bindList(url) {
callAjax(url, null, false, function (json) {
$('#myList').children().remove();
$('#myListTemplate').tmpl(json.d).appendTo('#myList');
});
}

This is a function I wrote to do just that. I'm not sure if it's faster than jQuery Templates. It creates and appends the Option elements one at a time, which may be slower than Templates. I suspect that Templates builds the whole HTML string, and then creates the DOM elements all in one shot. That may be a faster. I suppose this function could be adjusted to do the same thing. I've worked with Templates, and I do find that this function is easier to consume for something a simple as populating a Select list, and it fits nicely into my utility.js file.
Update: I updated my function to build the HTML first, and call append() only once. It actually runs much faster now. Thanks for posting this question, it's nice to be able to optimize one's own code.
Consuming the function
// you can easily pass in response.d from an AJAX call if it's JSON formatted
var users = [ {id: 1, name: 'Alice'}, {id: 2, name: 'Bob'}, {id: 3, name: 'Cindy'} ]
setSelectOptions($('#selectList'), users, 'id', 'name');
The function code
// Fill a select list with options using an array of values as the data source
// #param {String, Object} selectElement Reference to the select list to be modified, either the selector string, or the jQuery object itself
// #param {Object} values An array of option values to use to fill the select list. May be an array of strings, or an array of hashes (associative arrays).
// #param {String} [valueKey] If values is an array of hashes, this is the hashkey to the value parameter for the option element
// #param {String} [textKey] If values is an array of hashes, this is the hashkey to the text parameter for the option element
// #param {String} [defaultValue] The default value to select in the select list
// #remark This function will remove any existing items in the select list
// #remark If the values attribute is an array, then the options will use the array values for both the text and value.
// #return {Boolean} false
function setSelectOptions(selectElement, values, valueKey, textKey, defaultValue) {
if (typeof (selectElement) == "string") {
selectElement = $(selectElement);
}
selectElement.empty();
if (typeof (values) == 'object') {
if (values.length) {
var type = typeof (values[0]);
var html = "";
if (type == 'object') {
// values is array of hashes
var optionElement = null;
$.each(values, function () {
html += '<option value="' + this[valueKey] + '">' + this[textKey] + '</option>';
});
} else {
// array of strings
$.each(values, function () {
var value = this.toString();
html += '<option value="' + value + '">' + value + '</option>';
});
}
selectElement.append(html);
}
// select the defaultValue is one was passed in
if (typeof defaultValue != 'undefined') {
selectElement.children('option[value="' + defaultValue + '"]').attr('selected', 'selected');
}
}
return false;
}

Related

Compare HTML element with JSON array and replace

So I've been trying this for a while but no luck so far. What I want to achieve is, after selecting a value from the drop down, that value should be compared with the json multi-dimensional array. If it matches, then there are certain html elements on the webpage whose content needs to be replaced with the corresponding json values.
Here is the what I've been working so far (link)
<select onchange="executeMe(this)" id="selectOpt">
<option value="445">Choose...</option>
<option value="445">Daisy</option>
<option value="446">Romeo</option>
</select>
<br/><br/><br/>
<label id="entity_id">replaceThis</label>
So in the fiddle, if the user chooses "Daisy" from the dropdown, (the first array has Daisy in it) the corresponding value set from the array should be displayed in each of the html element on the webpage.
I can use only javascript for this. Thanks in advance guys...
You've got problems. First, your string you get back from your map function is massive and certainly won't pass an equality check with your option value. Additionally, your anonymous function is going to return the first value and not iterate through your for loop properly. There's no correlation between your select option values/labels and the items in the array. Try this:
function executeMe(select) {
var myselect = document.getElementById("selectOpt");
var selectOption = myselect.options[myselect.selectedIndex].innerHTML;
var i = theArray.length, obj, index, val;
while (i--) {
obj = theArray[i];
for (index in obj) {
val = obj[index];
//following matches on both keys and values, if you only
//want values delete the second part of the check
if (val == selectOption || index == selectOption) {
var string = '', prop;
for (prop in obj) {
string += prop + ': ' + obj[prop].toString() + '<br>';
}
document.getElementById('entity_id').innerHTML = string;
}
}
}
}
If this isn't what you need let me know with a comment.

js/jQuery - Converting array to string

The 2 drop downs I'm using to store into local storage are storing as an array.
How could I convert it where if any arrays are detected then convert it and store it as string instead?
Something like this?
if( Object.prototype.toString.call( value ) === '[object Array]' ) {
value.toString();
}
Please see my fiddle:http://jsfiddle.net/3u7Xj/137/
Showing being stored as:http://i.imgur.com/L78kGE7.jpg
local storage function:
save = function () {
$('input, select, textarea').each(function () {
var value = $(this).val();
var name = $(this).attr('name');
if($(this).hasClass('checkers')){
value = $(this).is(":checked")
if(value){
value='on';
}else{
value='off';
}
}
if(this.name.match(/^multiselect_/)){//removes buggy append
return false;
}
console.log('Saving');
console.log(name + ':' + value);
Survey[name] = value;
});
if (localStorage.getObj('Surveys') != null) {
Surveys = localStorage.getObj('Surveys');
}
Surveys[$('#FirstName').val() + '.' + $('#LastName').val()] = Survey; //store in big list
localStorage.setObj('Surveys', Surveys);
}
The easiest way to convert an array to a string is array.join(). Called just like that you get a comma-delimited string that contains all of the elements in the array. If you provide a separator (such as array.join('|')) you get a string that is delimited with the separator you provided. Where this fits into your saving function is up to you.
I would recommend using jQuery.encodeJSON()
http://forum.jquery.com/topic/jquery-encodejson
This way you can store your object as a JSON string.
You can then get your object back using the jQuery.parseJSON() function.
https://api.jquery.com/jQuery.parseJSON/
If i understood it right, i guess this could work:
Use Array.isArray method and then use JSON.stringify to turn the array into a string.
for (var key in this) {
//console.log(key, this[key]); //log to console
if($.isArray(this[key])) {
this[key] = this[key].join(':'); //change array to string separated by :
}
}

Populate a html dropdownlist from a comma delimted JSON object with distinct values

I have a JSON object that returns several key value pairs. One of which is a Languages key and this contains comma separated values e.g "English, Hindi,French" etc
What I require is to get the distinct values from the Language keys value and then into the following dropdown list.
The following is inputing the Language values into a dropdown but not handling the comma separating values, can someone help please.
Select a language_
$('#combolist-languages').html(function () {
var ret = '<option value="-1" selected>Select language_</option>',
u = user.slice(),
arr = [];
(function get() {
if (u.length) {
var v = u.shift();
if ($.inArray(v.Languages, arr) == -1) {
arr.push(v.Languages);
ret += '<option value="">' + v.Languages + '</option>';
}
get();
}
}());
return ret;
});
Example link -
31.222.187.42/hca-consulting/Farm/index.html
NOTE the following returns all the records from the db: Search by Name > Browse Names
You can use javascript spilt function and put the values into the array then pass it to the dropdown list.
For json key value pairs you can separate by "."

jQuery unwanted sorting of array output in Chrome and IE (FF working fine)

I have a jquery script which converts the options of a dropdown select box to ul list items using an array. Each option in the dropdown has a numerical option value, e.g.
<option value="12">Size S</option>
<option value="34">Size M</option>
<option value="7">Size L</option>
which get converted to a list like
<ul>
<li class="opt_12">Size S</li>
<li class="opt_34">Size M</li>
<li class="opt_7">Size L</li>
</ul>
In Firefox everything works as expected and the list items appear in the same order as the dropdown options. However IE and Chrome seem to sort the option values of the array automatically by option value in descending order.
So instead of size order S,M,L,XL like in the dropdown, in Chrome & IE I get a list with something like XL,M,S,L.
I noticed one thing: When I use var options = Array; to construct the array, Firefox displays the list elements in the right order and Chrome and IE the wrong one. When I use var options = [];, all three tested browsers display the list in the wrong order.
Below is the relevant code of the script which I use to transform the dropdown into list items:
(function($) {
$.fn.visualAttribute = function(options) {
var defaults = {
useTitle: false,
attrClicked : function(data) {
return true;
},
attrUpdated : function(data) {
}
};
var settings = $.extend(defaults, options);
//loop all attributes
var selectbox_counter = 0;
return this.each(function() {
//use counter for a unique class for each wrapper
selectbox_counter++;
//store reference to attribute selectbox
var selectbox = $(this);
//hide the default dropdown (but keep it in dom for posting the required values)
$(this).css('position', 'absolute').css('left', '-100000px').show();
//insert wrapper for options
var wrapper = $('<ul />')
.attr("class", "la_wrapper")
.attr("id", "la_wrapper_" + selectbox_counter)
.appendTo($(this).parent());
$(this).parent().append('<div style="clear:both"></div>');
if (selectbox.attr("id") != "") {
wrapper.attr("rel", selectbox.attr("id"));
}
//store all values of the dropdown in an array
var options = [];
var option_counter = 0;
var description = '';
selectbox.children('option').each(function() {
option_counter++;
if (option_counter == 1) {
//first option contains the description, e.g. 'please select size'
description = $(this).text();
}
//only use option if has a value
var value = $(this).val();
if (value != '') {
options[value] = ({value : value, text : $(this).text()});
}
});
//loop all stored options and create custom html
if (options.length) {
for (var index in options) {
if (!isNaN(index)) {
var value = index;
var text = options[index].text;
if (!settings.useTitle) {
description = '';
}
wrapper.append('<li title="' + description + '" class="opt_' + value + '">' + text + '</li>');
}
}
}
//set custom options to same value as current selectbox value (only needed in rare cases)
var current_value = selectbox.val();
if (current_value > 0) {
$("#la_wrapper_" + selectbox_counter + ' li.opt_' + current_value + ' a').addClass('selected');
}
//event handler for catching a clicked attribute
$("#la_wrapper_" + selectbox_counter + ' li a').click(function() {
var value = $(this).attr("href").split('#')[1];
//use callback
if (!settings.attrClicked(options[value])) {
return false;
}
//set value and class
selectbox.val(value);
$("#la_wrapper_" + selectbox_counter + ' .selected').removeClass('selected');
$(this).addClass('selected');
//use callback
settings.attrUpdated(options[value]);
return false;
});
});
};
})(jQuery);
How can I prevent IE and Chrome from "autosorting" the array and keep/transfer the original order of the dropdown options in the resulting list?
If the order is important, don't use the value of the option as the array key, just do an append (P.S. use [], not Array—that isn't doing what you think it's doing)
var options = [];
var option_counter = 0;
var description = '';
selectbox.children('option').each(function() {
option_counter++;
//only use option if has a value
var value = $(this).val();
if ( value ) {
options.push({value : value, text : $(this).text()});
}
});
Then, when looping, get rid of the if (options.length) altogether, and use a regular for loop:
for (var i=0; i<options.length; i++) {
var value = options[i].value;
var text = options[i].text;
if (!settings.useTitle) {
description = '';
}
wrapper.append('<li title="' + description +
'" class="opt_' + value +
'"><a href="#' + value + '">' + text +
'</a></li>');
}
When you iterate an array with this:
for (var index in options)
you are not getting a guaranteed order as you are just iterating properties of an object (not array indexes) which by specification have no guaranteed order. You should be using this:
for (var i = 0; i < options.length; i++)
to iterate an array in the array order. The first form iterates properties of an object in no particular order. The latter form iterates array elements in array index order (which gives you the actual array elements in their array order).
In addition, you declare an array with this:
var options = [];
or
var options = new Array();
You should not be using:
var options = Array;
Your problem is that you're using for...in to enumerate the properties.
Enumeration order for properties of an object (including an array) is undefined in ECMAScript so far. There is a proposal for ECMAScript 6 to define the order as follows, more or less: "first all properties whose names look like integers, in numeric order, then all other properties in the order they were added". This is the behavior Chrome and IE implement. The Firefox behavior is somewhat complicated and depends on whether your object is an array or not and if it's an array on which exact property names got used and in what order and what the length of the array is and a few other things.
In any case, if you want to enumerate the values in order, just store them in an array using array.push() and then enumerate the array's indices. So replace options[value] = ... with options.push(...) and replace for (var index in options) with for (var index = 0; index < options.length; ++index) and get the value from options[index].value just like you get the text already.

Populate dropdown select with array-with multiple options

So I'm trying to populate a dropdown with the states, the value for the option should be the two characters value, and the text for the option should be the full state's name, using the code below is returning a value of 0,1,2,3... and returning all the options in the var as the text.
var states = ["Select State","","Alabama","AL","Alaska","AK","Arizona","AZ","Arkansas","AR",...];
$.each(states, function(val, text) {
$('#selector').append( $('<option> </option>').val(val).html(text) )
});
Try this, using an object for states instead of an array. Same results, but it's more clear what's what and you're less likely to have problems if you accidentally skip a name or abbreviation:
var states = {
"Select State":"",
"Alabama":"AL",
"Alaska":"AK",
"Arizona":"AZ",
"Arkansas":"AR"
};
var val, text;
for (text in states) {
val = states[text];
$('<option/>').val(val).text(text).appendTo($('#selector'));
};
http://jsfiddle.net/g59U4/
The problem is that the callback function provided to .each results in val containing the index of the current iteration (e.g. 0, 1, 2 etc.) and text containing the value of that index of the array.
To achieve what you are trying to, you would probably be better off with a normal for loop:
for(var i = 0; i < states.length; i+=2) {
$("#selector").append($('<option> </option>').val(states[i+1]).html(states[i]));
}
You would be even better off caching the jQuery object containing #selector outside of your loop, so it doesn't have to look it up every iteration.
Here's a working example of the above.
Another option would be to use an object instead of an array, using the state name or abbreviation as the keys, and the other as the values. Edit: just like #mblase75 has done
Well you have the jQuery.each function arguments confused. The first is the index of the value in the array, and the second in the value itself. What you need to do is something like:
$.each(states, function(index) {
if(index%2 > 0) {
//continue, basically skip every other one. Although there is probably a better way to do this
return true;
}
$('#selector').append( $('<option> </option>').val(states[index+1]).html(states[index]) )
});
That would be really straightforward if your array had two dimensions. Considering you really need to use the one-dimensional array you presented, you could do this:
var states = ["Select State","","Alabama","AL","Alaska","AK","Arizona","AZ","Arkansas","AR"];
for(var i=1; i<states.length; i+=2) {
$('#selector').append( $('<option value="' + states[i] + '">' + states[i-1] + '</option>').val(val).html(text) )
}
If you changed your array to be an array of objects, you could do something like this -
var states = [{"text":"Select State","val":""},{"text":"Alabama","val":"AL"}]; //etc
$.each(states, function(val, statedata) {
$('#selector').append( $('<option> </option>').val(statedata.val).html(statedata.text) )
});
This change passes a JavaScript object in to the callback each time. The object has text and val properties and is passed in to the callback as the statedata parameter. The val parameter holds the current index position of the array so it is not required to populate the select box.
Demo - http://jsfiddle.net/sR35r/
I have a similar situation populating a select list with a two-dimensional array as the result of an $.ajax callback ....
JSON ...
[["AL","Alabama"],["AK","Alaska"],["AS","American Samoa"],["AZ","Arizona"] ...
var stateOptions = $('#state');
var html ='';
for (var i =1; i<data.length; i++){
html+= '<option value="' +data[i][0]+ '">' +data[i][1]+ '</option>';
}
stateOptions.append(html);
<form name="form" id="form">
<select name="state" id="state">
<option value=''>State</option>
</select>
</form>

Categories

Resources