Update one combobox by changing the second combobox - javascript

I want to update one combobox by changing the second combobox.
for example:
I have this response (string):
var response = [{
"A": "a2",
"B": "b2",
"C": "c2"
},
{
"A": "a3",
"B": "b3",
"C": "c3"
},
{
"A": "a3",
"B": "b331",
"C": "c33"
},
{
"A": "a3",
"B": "b33221",
"C": "c3"
},
{
"A": "a4",
"B": "b4",
"C": "c4"
},
{
"A": "a2",
"B": "b221",
"C": "c222"
}];
and I want that in "myDropDownA" will be "a2, a3, a4".
and for example:
if I choose "a3" in "myDropDownA", than in "myDropDownB" will appear only: "b3, b331, b33221" (because they only refer to a3).
and I don't want repeated of "A" objects.
var myDropDownA = $("#myDropDownA");
$.each(response, function (index, obj) {
//alert(index + ": " + obj.A);
myDropDownA.append($("<option />").val(obj.A).text(obj.A));
});
var myDropDownB = $("#myDropDownB");
$.each(response, function (index, obj) {
//alert(index + ": " + obj.B);
myDropDownB.append($("<option />").val(obj.B).text(obj.B));
});
what do I need to change (or to add) to make it work as above?

What you're missing is attaching an eventhandler to the change event of dropdown A repopulating dropdown B with relevant values.
var response = [
{ "A": "a2", "B": "b2", "C": "c2" },
{ "A": "a3", "B": "b3", "C": "c3" },
{ "A": "a3", "B": "b331", "C": "c33" },
{ "A": "a3", "B": "b33221", "C": "c3" },
{ "A": "a4", "B": "b4", "C": "c4" },
{ "A": "a2", "B": "b221", "C": "c222"}
];
var uniqueByProperty = function(arr, prop) {
var seen = {};
return arr.filter(function(elem) {
var val = elem[prop];
return (seen[val] === 1) ? 0 : seen[val] = 1;
})
}
var aList = uniqueByProperty(response, "A");
var myDropDownA = $("#myDropDownA");
var myDropDownB = $("#myDropDownB");
// Populate dropdown A
$.each(aList, function(index, obj) {
myDropDownA.append($("<option />").val(obj.A).text(obj.A));
});
// Attach event handler for dropdown A
myDropDownA.on('change', function(){
var ddl = $(this);
// Get related objects
var bList = response.filter(function(elem) {
return (elem.A === ddl.val());
});
// Populate dropdown B
myDropDownB.empty();
$.each(bList, function(index, obj) {
myDropDownB.append($("<option />").val(obj.B).text(obj.B));
});
});
// Trigger population of dropdown B
myDropDownA.change();
See this jsfiddle for a working demonstration.

Related

Iterate through nested JSON object array and store as key-value pair

I have to iterate through this JSON:
{
"data": 321563,
"group": [
{
"added": 42421,
"normal": {
"x": 39,
"y": "0.1300",
"b": "0.4326",
"c": "0.0552",
"f": 166833
},
"j": "240313",
"b": "0.2251",
"a": "dda",
"b": "0.101",
"a": 922,
"f": {
"c": 39,
"d": "0.263",
"a": "2.8955",
"h": "0.3211",
"d": 274
},
"a": false,
"k": 5,
"w": "0.072",
"d": "0.045",
"e": 3
},
I only want the j and k stored like a key value pair e.g. "j":k
I need to loop all of it, and store it to a file.
You can use a map to get a new array of items, this will not affect the old array.
const data = {
"game_count": 8750,
"sets": [
{
"appid": "221540",
"true_count": 9,
"bgs_avg": "0.10",
// Other data here
},
{
"appid": "123456",
"true_count": 9,
"bgs_avg": "0.20",
// Other data here
}
]
}
// Use "data.sets = data.sets.map(...)" to replace the data
// The following will only assign to a new variable
const newArray = data.sets.map(itm => { return {appid: itm.appid, true_count: itm.true_count} })
console.log(newArray)
We can also take the data and assign it directly back to the original overwriting it just by using data.sets = data.sets.map(...) as seen here:
const data = {
"game_count": 8750,
"sets": [
{
"appid": "221540",
"true_count": 9,
"bgs_avg": "0.10",
// Other data here
},
{
"appid": "123456",
"true_count": 9,
"bgs_avg": "0.20",
// Other data here
}
]
}
data.sets = data.sets.map(itm => { return {appid: itm.appid, true_count: itm.true_count} })
console.log(data)
In simple javascript this should work -
let newObj = {}
for(let i=0; i<obj.group.length; i++){
newObj[obj.group[i].j] = obj.group[i].k
}
Where 'obj' is your object
newObj will be you new Object which will contain all the key value pair

converting object properties which are array like to array is not working

I have an nested object like following(it can have any depth):
{
"a": 5,
"b": {
"0": 1,
"1": "x"
},
"x": {
"a": 1,
"1": "z"
},
"c": {
"0": 3,
"1": "Am",
"3":{
"0": 3,
"1": "x",
"2":{
"0": 3,
"1": "Y"
},
"length": 3
},
"length": 4
}
}
I have to convert it as following(object may or may not have length property):
{
"a": 5,
"x": {
"a": 1,
"1": "z"
},
"b": [1,"x"],
"c": [3, "Am",undefind, [ 3, "x", [ 3, "Y" ] ] ]
}
I written method like following:
function formatObjToArr(obj) {
var kys = Object.keys(obj);
var isObj = (/[^0-9]/g).test(kys.join('')) && !Array.isArray(obj);
if(!isObj){
obj.length===undefined && (obj.length = Math.max.apply(null,kys.map(function (i) { return parseInt(i) }))+1);
obj = Array.prototype.map.apply(obj,[function (i) { return i}]);
obj.forEach(function (i) {
(typeof i === "object" && i!==null) && formetObjToArr(i);
})
}else {
for (var property in obj) {
if (obj.hasOwnProperty(property) && property!=='length') {
if (typeof obj[property] === "object" && obj[property]!==null) {
formetObjToArr(obj[property]);
}
}
}
}
}
But it just adds the length property it is not changing the type. output of my code is as follows:
{
"a": 5,
"b": {
"0": 1,
"1": "x",
"length": 2
},
"x": {
"a": 1,
"1": "z"
},
"c": {
"0": 3,
"1": "Am",
"3": {
"0": 3,
"1": "x",
"2": {
"0": 3,
"1": "Y",
"length": 2
},
"length": 3
},
"length": 4
}
}
You could take a check for object and check if the keys are in the wanted range for an index or length, then create an array of it. This array should be converted, too.
function convert(object) {
var keys;
if (!object || typeof object !== 'object') {
return object;
}
keys = Object.keys(object);
if (keys.every(k => k === 'length' || Math.floor(k) === +k && k >= 0 && k < Math.pow(2, 31))) {
return Object.assign([], object).map(convert);
}
return Object.assign(...keys.map(k => ({ [k]: convert(object[k]) })));
}
var data = { a: 5, b: { 0: 1, 1: "x" }, x: { 1: "z", a: 1 }, c: { 0: 3, 1: "Am", "3": { 0: 3, 1: "x", 2: { 0: 3, 1: "Y" }, length: 3 }, length: 4 } };
console.log(convert(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }
var data = {
"a": 5,
"b": {
"0": 1,
"1": "x"
},
"c": {
"0": 3,
"1": "Am",
"length": 2
}
}
for(const d in data){
if(typeof data[d] === 'object'){
delete data[d]['length'];
data[d] = Object.values(data[d]);
}
}
console.log(data);

Normalise JSON object key names

I am wanting to write a function to turn a JSON object's keys into more appropriate names. As you can see by the JSON object below, the keys are 1 letter and are not very readable or useful for anyone. Therefore I would like to loop through the object (or something similar) and rename all the keys, and then return this JSON.
{
"e": "56049",
"pp": "371861",
"c": "GAME",
"x": 2,
"st": "2017-04-27T15:01:29Z",
"o": 0,
"r": true,
"u": "2017-04-27T15:01:29Z",
"t": "p",
"i": "371871",
"z": 1493305289586
}
You can reduce object keys to new object, e.g.:
const obj = {
"e": "56049",
"pp": "371861",
"c": "GAME",
"x": 2,
"st": "2017-04-27T15:01:29Z",
"o": 0,
"r": true,
"u": "2017-04-27T15:01:29Z",
"t": "p",
"i": "371871",
"z": 1493305289586
}
// [key] -> [normalized name] mapping
const names = {
"e": "e-name",
"pp": "pp-name",
"c": "c-name",
"x": "x-name",
"st": "st-name",
"o": "o-name",
"r": "r-name",
"u": "u-name",
"t": "t-name",
"i": "i-name",
"z": "z-name"
}
const renamedProps = Object.keys(obj).reduce((renamed, key) => {
renamed[names[key]] = obj[key];
return renamed;
}, {});
var obj = {
"e": "56049",
"pp": "371861",
"c": "GAME",
"x": 2
},
names = ["e_new-name", "pp_new-name", "c_new-name", "x_new-name"],
updated = {},
keys = Object.keys(obj);
for (i = 0; i < keys.length; i++) {
updated[names[i]] = obj[keys[i]];
}
console.log(JSON.stringify(updated));
// will print
// {"e_new-name":"56049","pp_new-name":"371861","c_new-name":"GAME","x_new-name":2}
jsfiddle

Flatten and merge array of array of objects in Javascript

Here is my input:
var toto=[
[
{ "a": "24" },
{ "a": "23.9"},
{ "a": "NaN"},
{ "a": "3" }
],
[
{"b": "19"},
{"b": "20"},
{"b": "NaN"},
{"b": "3" }
],
[
{"c": "27"},
{"c": "28"},
{"c": "NaN"},
{"c": "3" }
]
];
All arrays of objects are guaranteed to contain the same number of objects.
I would like to obtain in output:
var out = [
{ "a": "24", "b": "19", "c":"27" },
{ "a": "23.9", "b": "20", "c":"28"},
{ "a": "NaN", "b": "NaN", "c":"NaN"},
{ "a": "3", "b": "3", "c": "3"}
]
Which is, for each inner array, take the Nth element and merge it into an object, and push it into a result array.
I have a "braindead" solution which is iterating on the first sub-array and then iterating on the other arrays:
var out = [];
$(toto[0]).each(function(i, item) {
var o = {};
$(toto).each(function( j, array) {
var item = array[i];
o[Object.keys(item)[0]] = Object.values(item)[0];
});
out.push(o);
});
It works, but it is kind of hideous, and I would like to know if there's a solution using functional methods like map and reduce.
Do you guys know?
You could use Array#reduce, Array#forEach and Object.assign for a pivot of the data with the same index for the inner array.
var toto=[[{ a: "24" }, { a: "23.9" }, { a: "NaN" }, { a: "3" }], [{ b: "19" }, { b: "20" }, { b: "NaN" }, { b: "3" }], [{ c: "27" }, { c: "28" }, { c: "NaN" }, { c: "3" }]],
result = toto.reduce(function (r, a) {
a.forEach(function (b, i) {
r[i] = r[i] || {};
Object.assign(r[i], b);
});
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

d3.nest() sum for object array data

I have data in the format of
data={
"Month": "Jan",
"typeA": [
{
"A": 24000,
"B": 24000,
"C": 24000
}],
"typeB": [
{
"A": 20000,
"B": 14000,
"C": 10000
}],
"typeC": [
{
"A": 34000,
"B": 44000,
"C": 54000
}]
},
{
"Month": "Feb",
"typeA": [
{
"A": 84000,
"B": 64000,
"C": 14000
}],
"typeB": [
{
"A": 20000,
"B": 34000,
"C": 10000
}],
"typeC": [
{
"A": 30000,
"B": 40000,
"C": 50000
}]
}
]
I want to calculate sum of each type( ie typeA, TypeB) for indivisual months,
Ie I want data in the format below,
Month: jan
typeA:72000
typeB:44000
typeC:13200
Month:feb
typeA:162000
typeB:64000
typeC:120000
I am using d3.nest() to achieve this,
This is my code,
var months= d3.nest()
.key(function (d) { return (d.Month) })
.key(function (d) { return (d.typeA) })
.key(function (d) { return (d.typeB) })
.key(function (d) { return (d.typeC) })
.rollup(function (leaves) {
return d3.sum(leaves, function (d) { return d3.sum(sum,d3.values(d.A,d.B,d.C,d.D)) });
})
.entries(data);
I am not able to get the sum of the elements here. I'm getting zero as sum. Can anybody suggest me where I am doing wrong?
Unfortunately my other answer was for a different question but I'll leave it in case it's useful.
The answer by #Gabriel is very cool but is using d3 functions but its not generic and the categories are hard-coded in which is not ideal.
Here is a way to do it in (mostly) plain JS that is completely generic. The only assumption is that the first member of each array element is the heading being grouped and the other members are the ones to be rolled up. Anyway, as well as generic, this way is quite short.
I also included a version of the #Gabriel answer to show it's easy to generalise also.
var data = [{
"Month": "Jan",
"typeA": [
{
"A": 24000,
"B": 24000,
"C": 24000
}],
"typeB": [
{
"A": 20000,
"B": 14000,
"C": 10000
}],
"typeC": [
{
"A": 34000,
"B": 44000,
"C": 54000
}]
},
{
"Month": "Feb",
"typeA": [
{
"A": 84000,
"B": 64000,
"C": 14000
}],
"typeB": [
{
"A": 20000,
"B": 34000,
"C": 10000
}],
"typeC": [
{
"A": 30000,
"B": 40000,
"C": 50000
}]
}],
//////////////////////////////////////////////////////////////////////////////////
//Method one: without rollup
// assume that the first member of each object in the array is a heading
// e.g. Month
//////////////////////////////////////////////////////////////////////////////////
headings = data.reduce(function(headings, d) {
var h = d3.keys(d)[0]; //get the heading
return (headings [d[h]] = d3.keys(d).filter(function(p, i){return i}) //filter out the heading
.reduce(function(s, p){ //sum each of the other members
//p is the category being summed
return (s[p] = d3.sum(d3.values(d[p][0])), s);
}, {}), headings);
}, {});
d3.select("#output").text(JSON.stringify(headings));
//////////////////////////////////////////////////////////////////////////////////
//Method two: #Gabriel solution generalised
//////////////////////////////////////////////////////////////////////////////////
var months = d3.nest()
.key(function(d) { return (d.Month) })
.rollup(function (v) {
return d3.keys(v[0]).filter(function(p, i){return i}) //filter out the heading
.reduce(function(s, p){ //sum each of the other members
//p is the category being summed
return (s[p] = d3.sum(d3.values(v[0][p][0])), s);
}, {});
})
.map(data);
d3.select("#output2").text(JSON.stringify(months));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="output"></div></br>
<div id="output2"></div>
I am not much familiar with d3.nest. But I think you can get your results by using JavaScript Array map function. Try this code.
var data=[{
"Month": "Jan",
"typeA": [
{
"A": 24000,
"B": 24000,
"C": 24000
}],
"typeB": [
{
"A": 20000,
"B": 14000,
"C": 10000
}],
"typeC": [
{
"A": 34000,
"B": 44000,
"C": 54000
}]
},
{
"Month": "Feb",
"typeA": [
{
"A": 84000,
"B": 64000,
"C": 14000
}],
"typeB": [
{
"A": 20000,
"B": 34000,
"C": 10000
}],
"typeC": [
{
"A": 30000,
"B": 40000,
"C": 50000
}]
}
];
var results = data.map(function(d){
return {
Month: d.Month ,
typeA: d3.sum(d3.values(d.typeA[0])),
typeB: d3.sum(d3.values(d.typeB[0])),
typeC: d3.sum(d3.values(d.typeC[0]))
}
});
alert(JSON.stringify(results));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
You can do it with nesting like this...
data = [{
"Month": "Jan",
"typeA": [
{
"A": 24000,
"B": 24000,
"C": 24000
}],
"typeB": [
{
"A": 20000,
"B": 14000,
"C": 10000
}],
"typeC": [
{
"A": 34000,
"B": 44000,
"C": 54000
}]
},
{
"Month": "Feb",
"typeA": [
{
"A": 84000,
"B": 64000,
"C": 14000
}],
"typeB": [
{
"A": 20000,
"B": 34000,
"C": 10000
}],
"typeC": [
{
"A": 30000,
"B": 40000,
"C": 50000
}]
}],
months = d3.nest()
var months = d3.nest()
.key(function(d){return d.Month})
.rollup(function(leaves){
//leaves is an array so use d3.sum
return d3.sum(leaves, function(d) {
//d can be an object who's value can be an array
//use d3.sum
return d3.sum(d3.values(d), function(e){
//
return d3.sum(e, function(f) {
return d3.sum(d3.values(f))
});
})
} )
})
.entries(data);
d3.select("#output").text(JSON.stringify(months));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="output"></div>
You just need to change your code like this:
Add ]; end of data
data = [
{
"Month": "Jan",
"typeA": [
{
"A": 24000,
"B": 24000,
"C": 24000
}
],
"typeB": [
{
"A": 20000,
"B": 14000,
"C": 10000
}
],
"typeC": [
{
"A": 34000,
"B": 44000,
"C": 54000
}
]
},
{
"Month": "Feb",
"typeA": [
{
"A": 84000,
"B": 64000,
"C": 14000
}
],
"typeB": [
{
"A": 20000,
"B": 34000,
"C": 10000
}
],
"typeC": [
{
"A": 30000,
"B": 40000,
"C": 50000
}
]
}
];
Change your code to:
var months = d3.nest()
.key(function(d) { return (d.Month) })
.rollup(function (v) {
return {
typeA: d3.sum(d3.values(v[0].typeA[0])),
typeB: d3.sum(d3.values(v[0].typeB[0])),
typeC: d3.sum(d3.values(v[0].typeC[0]))
} })
.map(data);
console.log(JSON.stringify(months));
Edit:
You can use this type of d3.sum() function too, But remember the value's that return are string 'the part that you missed in your code' to see the actual result need to parse data.
var months = d3.nest()
.key(function(d) { return (d.Month) })
.rollup(function(v) {
return {
typeA: d3.sum(v, function(d) {
var type = d3.values(d.typeA[0]);
var array = type.map(function (x) { return parseInt(x, 10) });
return d3.sum(array);
}),
typeB: d3.sum(v, function (d) {
var type = d3.values(d.typeB[0]);
var array = type.map(function (x) { return parseInt(x, 10) });
return d3.sum(array);
}),
typeC: d3.sum(v, function (d) {
var type = d3.values(d.typeC[0]);
var array = type.map(function (x) { return parseInt(x, 10) });
return d3.sum(array);
})
}
})
.entries(data);
console.log(JSON.stringify(months));

Categories