underscore js _grouby Browser Difference - javascript

I'm seeing some strange behavior with the order in which a select's optgroups and options are being rendered. I have some data that is used to build optgroup in a select and then options using the underscore js _grouby function. Firefox is rendering the data the way I ordered the json, Chrome and IE are displaying it in reverse order.
Here's a Fiddle
Html:
<select name="dropdownlist" id="dropdownlist">
<option value="All">All</option>
</select>
JavaScript:
$(document).ready(function() {
var dataresults = [{"MonthName":"April","Month":4,"Year":2014,"Date":"\/Date(1397451600000)\/"},{"MonthName":"January","Month":1,"Year":2014,"Date":"\/Date(1388556000000)\/"},{"MonthName":"November","Month":11,"Year":2013,"Date":"\/Date(1384322400000)\/"},{"MonthName":"July","Month":7,"Year":2013,"Date":"\/Date(1373864400000)\/"}];
BindYearDropDown(dataresults);
function BindYearDropDown(data)
{
var groupData = _.groupBy(data, function (obj) {
return obj.Year;
});
var optGroups = [];
for (var key in groupData) {
if (groupData.hasOwnProperty(key)) {
var optGroup = $("<optgroup></optgroup>");
optGroup.attr("label", key);
optGroup.attr("id", key);
var currentGroup = groupData[key];
for (var i = 0; i < currentGroup.length; i++) {
$("<option />").attr("value", currentGroup[i].Month).html(currentGroup[i].MonthName).appendTo(optGroup);
}
optGroups.push(optGroup);
}
}
//optGroups.reverse();
for (var i = 0; i < optGroups.length; i++) {
$('#dropdownlist').append(optGroups[i]);
}
};
FireFox Results: (This is how I would like the data displayed)
Chrome Results:
IE11 Results:
Thanks in advance,
KC

If you really want to work with the data in the structure you provided, you can create a list of years and then sort that. Otherwise, I recommend what #mu is too short suggested. jsfiddle
/* reusable descending sort function */
function sortDescending(value) {
return value * -1;
};
...
var groupData = _.groupBy(data, function (obj) {
return obj.Year;
});
/* Sort the years in descending order */
var years = _.sortBy(_.keys(groupData), sortDescending);
var optGroups = [];
for (var index in years) {
var key = years[index];
...

Related

Pass Multiple Select Values to a Javascript API function

I will keep this simple. First, these are snippets extracted from a larger document. So yes, I have the proper headers and source references, etc.
I have a select box. I know how to call the function based on a single value selection. I want to know how specifically to call this function showOnly() when the select box allows for multiple values.
The select box is
<select id="select_a" name="color" multiple>
<option selected="selected" class="options">Select desired detail</option>
<option value="None" class="options" >None</option>
<option value="Investment Category" class="options">Investment Category</option>
<option value="Company" class="options">Company</option>
<option value="Budget Line" class="options">Budget Line</option>
<option value="Market" class="options">Market</option>
<option value="Organization" class="options">Organization</option>
<option value="Segment" class="options">Segment</option>
</select>
So, how do I connect multiple values to the function showOnly() below. With one value, showOnly() might look like this showOnly('Segment','Cars'). I know showOnly with multiple values would like showOnly('Segment,['Cars','Boats','Planes']). Here is the function showOnly()
function showOnly(filterName, values) {
sheet = mainViz.getWorkbook().getActiveSheet();
if(sheet.getSheetType() === 'worksheet') {
sheet.applyFilterAsync(filterName, values, 'REPLACE');
} else {
worksheetArray = sheet.getWorksheets();
for(var i = 0; i < worksheetArray.length; i++) {
worksheetArray[i].applyFilterAsync(filterName, values, 'REPLACE');
}
}
};
Thoughts?? //Thanks for your consideration.
var colOfSelectedOpt = document.getElementById("select_a").selectedOptions;
var values = [];
for(var i=0;i<colOfSelectedOpt.length;i++) {
values.push(colOfSelectedOpt[i].value);
}
values should give you array of selected items. You can pass this to function before calling or pass the id of select and get values inside function.
Update
function showOnly(filterName, idOfSelect) {
var colOfSelectedOpt = document.getElementById(idOfSelect).selectedOptions;
var values = [];
for(var i=0;i<colOfSelectedOpt.length;i++) {
values.push(colOfSelectedOpt[i].value);
}
sheet = mainViz.getWorkbook().getActiveSheet();
if(sheet.getSheetType() === 'worksheet') {
sheet.applyFilterAsync(filterName, values, 'REPLACE');
} else {
worksheetArray = sheet.getWorksheets();
for(var i = 0; i < worksheetArray.length; i++) {
worksheetArray[i].applyFilterAsync(filterName, values, 'REPLACE');
}
}
};
Whenever you call showOnly() method pass the id of select dom for which you want this function to get called.
<select id="select_a" name="color" onchange="showOnly('filterName', this.getAttribute('id'));" multiple>
Or If you want selection to work on some other button then fetch and id from associated select dropdown by id and pass it to function.
There's an object built-in Function as a property called arguments which is a local variable that can pass in an unlimited amount of values. arguments is array-like in that it will index every value it's given and it has a couple of methods including length. I have no idea if my example works since half of those functions and variables are not provided. collArgs() should be able to take a number of parameters and return the values in an indexed array-like fashion. From there, I've assigned values to store the values of arguments and now it can be passed into your functions.
Please read this article for a better explanation and working examples
args = new arguments()
function collArgs() {
for (var i = 0; i < arguments.length; i++) {
arguments[i];
}
return arguments;
}
var values = collArgs();
function showOnly(filterName, values) {
var sheet = mainViz.getWorkbook().getActiveSheet();
if(sheet.getSheetType() === 'worksheet') {
sheet.applyFilterAsync(filterName, values, 'REPLACE');
} else {
var worksheetArray = sheet.getWorksheets();
for(var i = 0; i < worksheetArray.length; i++) {
worksheetArray[i].applyFilterAsync(filterName, values, 'REPLACE');
}
}
};
Since HTMLOptionsCollection's are array-like objects, I'm not familiar with any way to use Array.prototype.map() to create a new array of selected values. But we can alway use the good old fashioned for loop. Here's an ES6 approach:
const select = document.getElementById('select_a');
const on_change = (event) => {
const options = event.target.options;
let values = [];
for (var i = 0; i < options.length; i++) {
if (options[i].selected) {
values.push(options[i].value);
}
}
console.log('Pass these values to your function:', values);
};
select.addEventListener('change', on_change);
JS Bin: http://jsbin.com/yemoxizaso/1/edit?js,console,output
And if you can't use ES6, here's an ES5 approach:
var select = document.getElementById('select_a');
var on_change = function(event) {
var options = event.target.options;
var values = [];
for (var i = 0; i < options.length; i++) {
if (options[i].selected) {
values.push(options[i].value);
}
}
console.log('Pass these values to your function:', values);
};
select.addEventListener('change', on_change);

storing dc.js filters in URI and restoring them

Here i selected 3 filters 1 from each chart and pasted that encoded url in url param. but when i press decode url button it is redrawing only middle chart filters but not the remaining once.. what should i do?
thanks
function encodeFunction()
{
var filters = [];
for (var i = 0; i < dc.chartRegistry.list().length; i++)
{
var chart = dc.chartRegistry.list()[i];
for (var j = 0; j < chart.filters().length; j++)
{
filters.push({ChartID: chart.chartID(), Filter: chart.filters()[j]});
}
}
var urlParam = encodeURIComponent(JSON.stringify(filters));
alert(urlParam);
}
function decodeFunction()
{
//encoded url here
var urlParam="%5B%7B%22ChartID%22%3A1%2C%22Filter%22%3A2012%7D%2C%7B%22ChartID%22%3A2%2C%22Filter%22%3A%5B1.0454545454545454%2C4.045454545454545%5D%7D%2C%7B%22ChartID%22%3A3%2C%22Filter%22%3A%22Mr%20B%22%7D%5D ";
var filterObjects = JSON.parse(decodeURIComponent(urlParam));
for (var i = 0; i< filterObjects.length; i++)
{
dc.chartRegistry.list()[filterObjects[i].ChartID-1].filter(filterObjects[i].Filter);
}
// dc.renderAll();
dc.redrawAll();
}
here is the fiddle: js fiddle link
It looks like your code is correct for the general case, but due to some quirks in the way that dc.js handles filters, you can't just restore a range filter from its serialized form.
I was able to get it working by adding a special case for arrays:
for (var i = 0; i< filterObjects.length; i++)
{
var filter = filterObjects[i].Filter;
if(filter instanceof Array) filter = dc.filters.RangedFilter(filter[0], filter[1]);
dc.chartRegistry.list()[filterObjects[i].ChartID-1].filter(filter);
}
Here is my fork of your fiddle: http://jsfiddle.net/gordonwoodhull/4dv93aht/10/
I don't think such special cases should be needed, so I opened an issue here: https://github.com/dc-js/dc.js/issues/819
Have a look at this question & working example
dc.js permalink or href to share the visualisation filter state?
https://github.com/Edouard-Legoupil/3W-Dashboard/blob/gh-pages/index.html

Sort JSON array based on value with jQuery

I've got two dropdown select dropdowns: one for regions and one for cities in the selected region. The result is loaded by AJAX and in my response i get all cities in an JSON array:
{
1709: "Geertruidenberg",
1710: "Netersel",
1711: "Macharen",
1712: "Beers",
1713: "Hank",
1714: "Oudemolen",
1715: "Nistelrode"
}
I'm using this small plugin to load the data in the select dropdown:
(function($, window) {
$.fn.replaceOptions = function(options) {
var self, $option;
this.empty();
self = this;
$.each(options, function(index, option) {
$option = $("<option></option>")
.attr("value", index)
.text(option);
self.append($option);
});
};
})(jQuery, window);
And this piece of javascript to do the AJAX request:
$('select#Profile_regionId').change(function() {
$.post('/ajax/getcities', {regionid: $(this).val()}, function(data){
//console.log(data.cities);
$("select#Profile_cityId").replaceOptions(data.cities);
}, 'json');
});
All works totally fine, except the city dropdown is automatically sorted on the JSON array key. I tried to use the sort() method for this, but it won't work because it's an Object and not an array. Then i tried to create an array of it:
var values = [];
$.each(data.cities, function(index,value)) {
values[index] = value;
}
But for some reason, the dropdown list fills itself up from 1 to the first found id (key of array) of the city, and i don't know why it's doing that (array itself looks fine).
How can i sort the thing so my cities are ordered alphabetically in the dropdown list?
It needs to be converted to an array so that it can be sorted. Let's assume this is your object. Note that I rearranged it to be unsorted, to prove this works.
originalData = {
1712: "Beers",
1709: "Geertruidenberg",
1710: "Netersel",
1713: "Hank",
1714: "Oudemolen",
1711: "Macharen",
1715: "Nistelrode"
};
Now to create an array version we need to create an array, and insert objects into it. I'm calling the keys "year". Note that we're calling parseInt on the keys. Keys in JavaScript (except for arrays) are always strings. For example, {foo: "bar"} has a string key "foo". This also applies to numerical looking keys.
var dataArray = [];
for (year in originalData) {
var word = originalData[year];
dataArray.push({year: parseInt(year), word: word});
}
There's a chance that we have our data out of sort right now, so we manually sort it. Note that this is a case sensitive sort. For example, "Qux" comes before "foo".
dataArray.sort(function(a, b){
if (a.word < b.word) return -1;
if (b.word < a.word) return 1;
return 0;
});
The function now just pulls option.year and option.word from our array.
$.fn.replaceOptions = function(options) {
var self, $option;
this.empty();
self = this;
$.each(options, function(index, option) {
$option = $("<option></option>")
.attr("value", option.year)
.text(option.word);
self.append($option);
});
};
And then you finally use the plugin, passing the array. You can put all of this code in the plugin, if that works best for you.
$('#mylist').replaceOptions(dataArray);
fiddle
This will do what you want and take care of the empty ids/undefined values:
var data = {
1709: "Geertruidenberg",
1710: "Netersel",
1711: "Macharen",
1712: "Beers",
1713: "Hank",
1714: "Oudemolen",
1715: "Nistelrode"
};
var values = [];
$.each(data, function(index, value) {
values[index] = value;
});
values.sort();
$.each(values, function(index, value) {
if(value != undefined) {
$("#Profile_cityId").append("<option>"+ value +"</option");
}
});
Just replace the append I put in with your own function because jsFiddle was giving me trouble using that. Demo: http://jsfiddle.net/R4jBT/3/
So here is how I would do it. I assume that you are getting an AJAX response that comes like:
results: [
{year: 1709, city: "Geertruidenberg"},
{year: 1710, city: "Netersel"},
{year: ..., city: ...}
]
And, in a standard AJAX call, you would run through them like this, in a success function:
success: function(data) {
var results = data.results;
if (results.length > 0) {
for (i=0; i < results.length; i++) {
dataArrayOrig.push({
"id" : results[i].year,
"label" : results[i].city
});
}
}
},
I saw you say you do your call like this:
$.post('/ajax/getcities', {regionid: $(this).val()}, function(data){
//console.log(data.cities);
$("select#Profile_cityId").replaceOptions(data.cities);}, 'json');
You're not doing anything tests on data to see if it has results (ex. if (data.length > 0) { ... }), and you would need to push those results to an original array that stays pristine and another that can be sorted, then a final one that can get back the original year to the label, that the dropdown can then receive.
If you do it as I showed, above, you can integrate the lines I gave into the function(data){ ... } area.
Right after the push to the dataArrayOrig object, you can push to a new array you can use to sort with, using a comparison function to determine if the label (city) should come before or after the previous entry:
var results = data.results;
if (results.length > 0) {
for (i=0; i < results.length; i++) {
dataArrayOrig.push({
"id" : results[i].year,
"label" : results[i].city
});
dataArraySorting.push({
"id" : results[i].year,
"label" : results[i].city
});
dataArraySorting.sort(compare);
JSON.stringify(dataArraySorting); // sorted cities, but will be mismatched to the years
}
}
The comparison function:
function compare (a, b) {
if (a.label < b.label)
return -1;
if (b.label < a.label)
return 1;
return 0;
});
You could also do this inline:
dataArraySorting.sort(function(a, b){
if (a.label < b.label) return -1;
if (b.label < a.label) return 1;
return 0;
});
I prefer the function approach since then it can be re-used. We will see the usefulness of that in a minute.
For your arrays, declare them at the top, before your functions:
var dataArrayOrig = [];
var dataArraySorting = [];
var dataArraySorted = [];
So after that loop that goes through the results, start another one that goes through the "sorting" array and compares its label against the one in the original array we pushed to and pulls out the original ID (Year):
for (var j=0; j < dataArraySorting.length; j++) {
for (var k=0; k < dataArrayOrig.length; k++) {
if (dataArraySorting[j].label == dataArrayOrig[k].label) {
dataArraySorted.push({
"id" : dataArrayOrig[k].id,
"label" : dataArraySorting[j].label
});
console.log("Sorted ID: " + dataArrayOrig[k].id + ", Sorted label: " + dataArraySorting[j].label);
dataArraySorted.sort(compare);
JSON.stringify(dataArraySorted); // array of sorted cities, matched to year
}
}
}
You would go on to apply that dataArraySorted array to your dropdown as normal. I tested to see if I got more than 0 items from the original AJAX call, then I appended the options using id and label from the array's property names:
if (dataArraySorted.length > 0) {
$.each(dataArraySorted, function() {
$("#combobox").empty().append($("<option></option>").val(this['id']).html(this['label'));
});
}
JSFiddle with the results.

How to convert json to java script array?

I have the json string like,
string js=[{"Name":"Pini","ID":"111"},
{"Name":"Yaniv","ID":"123"},
{"Name":"Yoni","ID":"145"}]
And I need to convert this into like the following format using java script.
[['Pini',111],['Yaniv',123],['Yoni',145]]
How to convert the json string into javascript array using javascript function?
I think something like this:
var ret = [];
for (var i = 0; i < js.length; i++) {
ret.push([js[i].Name, js[i].ID]);
}
// ret holds your array of arrays
Or something like:
var ret = $.map(js, function (el, i) {
return [[el.Name, el.ID]];
});
An example of both: http://jsfiddle.net/RNY8M/
You can do like this
JsFiddler Demo of below code
var JSONObject = {"results":[{"Name":"Pini","ID":"111"},
{"Name":"Yaniv","ID":"123"},
{"Name":"Yoni","ID":"145"}]};
var Users= [];
$.each(JSONObject.results, function(i, obj)
{
alert(obj.Name);
alert(obj.ID);
Users.push([obj.Name, obj.ID]);
});​
For this kind of transformations I always prefer using UnderscoreJs which is an utility-belt library (mainly for object/array transformations) for Javascript. I think that it provides great functions that make life easier, allowing javascript developers to be more productive and to achieve a better legibility for the resulting code.
Here is the solution with underscore (extended):
var js=[{"Name":"Pini","ID":"111"},
{"Name":"Yaniv","ID":"123"},
{"Name":"Yoni","ID":"145"}]
var names = _.pluck(js, 'Name');
var ids = _.pluck(js, 'ID');
var result = _.zip(names, ids)
And you achive the desired result:
[['Pini',111],['Yaniv',123],['Yoni',145]]
Solution in one line with underscorejs:
var result = _.zip(_.pluck(js, 'Name'), _.pluck(js, 'ID'))
Hope it helps!
Here's a solution that will work for a simple object (not deep objects, though.... but I'll leave that for you to implement).
http://jsfiddle.net/eUtkC/
var js = [{
"Name": "Pini",
"ID": "111"},
{
"Name": "Yaniv",
"ID": "123"},
{
"Name": "Yoni",
"ID": "145"}]
function obj2arr(obj) {
var i, key, length = obj.length,
aOutput = [],
aObjValues;
for (i = length - 1; i >= 0; i--) {
aObjValues = [];
for (key in obj[i]) {
if (obj[i].hasOwnProperty(key)) {
aObjValues.push(obj[i][key]);
}
}
aOutput.push(aObjValues);
}
return aOutput;
}
document.write(JSON.stringify(obj2arr(js)))​
EDIT
Here's a version using Array.prototype.map:
http://jsfiddle.net/eUtkC/1/
function obj2arr(obj) {
var key, aOutput = [];
for (key in obj) {
if (obj.hasOwnProperty(key)) {
aOutput.push(obj[key]);
}
}
return aOutput;
}
document.write(JSON.stringify(js.map(obj2arr)))​
I correct my solution, I hadn't read well the specs (my fault):
var jsonArray = [{"Name":"Pini","ID":"111"}, {"Name":"Yaniv","ID":"123"}, {"Name":"Yoni","ID":"145"}];
var jsonConverted = {};
$(jsonArray).each( function() {
jsonConverted.push([ this.Name, this.ID ]);
});
This solution uses jQuery.

JavaScript: get value of dropdown

I have 3 HTML combo/drop down boxes. All of them have a distinct name and id.
On a particular event I want to get the value of all three of them.
Can any one give me a code snippet for that?
using jQuery:
$("#dropdownID").val();
I'd try to set them up next to each other in your HTML and then iterate through them using jQuery's built-in each() method. You'd set up your elements like this:
<div id="dropdownBoxes">
<select id="firstElement">
<option>cool</option>
<option>neat</option>
</select>
<select id="secondElement">
<option>fun</option>
<option>awesome</option>
</select>
<select id="thirdElement">
<option>great</option>
<option>synonym</option>
</select>
</div>
<input type="button" id="theTrigger">Push me!</input>
Then, in your script:
var dropdownValues;
$("#theTrigger").click(function(){
dropdownValues.length=0;
$("#dropdownBoxes select").each(function(){
dropdownValues.push($(this).val());
});
});
To do this not using jQuery:
function getSelectValues() {
var values = [];
for (var i = 0; i < arguments.length; i++) {
var select = document.getElementById(arguments[i]);
if (select) {
values[i] = select.options[select.selectedIndex].value;
} else {
values[i] = null;
}
}
return values;
}
This function returns an array of values that correspond to the ids you pass into the function, as follows:
var selectValues = getSelectValues('id1', 'id2', 'id3');
If a <select> with one of your specified ids does not exist the array contains null for the value for that position.
There are a couple of other ways to do this, you could pass the function an array of id values: getSelectValues([ 'id1', 'id2', 'id3' ]), in which case the function would be changed:
function getSelectValues(ids) {
var values = [];
for (var i = 0; i < ids.length; i++) {
// ...
You could also pass the function a map of ids and populate the values:
var myMap = { 'id1': null, 'id2': null, 'id3': null };
getSelectValues(myMap);
// myMap['id1'] contains the value for id1, etc
This would change the function to be:
function getSelectValues(map) {
for (var id in map) {
var select = document.getElementById(id);
if (select) {
map[id] = select.options[select.selectedIndex].value;
} else {
map[id] = null;
}
}
}
Use a framework like jQuery mentioned above or just do it the old school way. document.getElementById('dropdownId').value .

Categories