creating nested array javascript - javascript

Have looked at many examples but cant seem to get to make an nested array to store some data nicely. How can I get the following code to work? It gives me an error now:
var shipdata = [];
shipdata['header']['bedrijfsnaam'] = $('[name="bedrijfsnaam"]').val();
shipdata['header']['naam'] = $('[name="naam"]').val();
shipdata['header']['straat'] = $('[name="straat"]').val();
shipdata['header']['postcode'] = $('[name="postcode"]').val();
shipdata['header']['plaats'] = $('[name="plaats"]').val();
shipdata['header']['telefoon'] = $('[name="telefoon"]').val();
shipdata['header']['email'] = $('[name="email"]').val();
shipdata['header']['instructies'] = $('[name="instructies"]').val();
shipdata['header']['ordernummertje'] = $('[name="ordernummertje"]').val();
$(".pakketten").each(function(index, element) {
index++;
shipdata['pakketten']['pakket'+index]['lengte'] = $('[name="lengte'+index+'"]').val(),
shipdata['pakketten']['pakket'+index]['breedte'] = $('[name="breedte'+index+'"]').val(),
shipdata['pakketten']['pakket'+index]['hoogte'] = $('[name="hoogte'+index+'"]').val(),
shipdata['pakketten']['pakket'+index]['gewicht'] $('[name="gewicht'+index+'"]').val()
});
Probably im doing this all wrong, but some pointers would be welcome.
Thanks!

First of all, you are creating an object and not an array, so use {} instead of [] for the main container.
Second, when inserting multiple values at the same time, you can use a much more compact notation:
var shipdata = {
'header': {
'bedrijfsnaam': $('[name="bedrijfsnaam"]').val(),
'naam': $('[name="naam"]').val()
'...': '...'
},
'pakketten': []
};
$(".pakketten").each(function(index, element) {
shipdata['pakketten'].push({
'lengte': $('[name="lengte'+index+'"]').val(),
'breedte': $('[name="breedte'+index+'"]').val(),
'...': '...'
});
});
Besides, anytime you want to access an object or array in any way, you have to initialize it beforehand as already mentioned by #antyrat.

You need to create objects each time you want to have nested array:
var shipdata = {};
shipdata['header'] = {};
shipdata['header']['bedrijfsnaam'] = $('[name="bedrijfsnaam"]').val();
//...
shipdata['pakketten'] = {};
$(".pakketten").each(function(index, element) {
index++;
shipdata['pakketten']['pakket'+index] = {};
shipdata['pakketten']['pakket'+index]['lengte'] = $('[name="lengte'+index+'"]').val(),
// ...
Answer updated due to comments as arrays didn't have string indexes.

Related

Create JSON with multiple values

I need to create a JSON with data every time I click on a button BTN. Here is how I create my JSON :
$(document).ready(function () {
var maj = {};
$("#btnSubmitRejetRefModele").click(function() {
maj['one'] = 'a'
maj['two'] = 'b'
maj['three'] = 'c'
}
Values a,b,c are changing every time and I want to store each value in a JSON with the structure :
maj = {
"0" : {'one':'a','two':'b','three':'b'} ,
"1" : {'one':'a2','two':'b2','three':'c2},
// ...
}
How can I code and append my data in my JSON each time I click on the button. This JSON will be used in a post method to insert values into PGsql
You need to check the size of the current object, and insert the data to the position of that size:
$(document).ready(function() {
var maj = {};
$("#btnSubmitRejetRefModele").click(function() {
var size = Object.keys(maj).length;
var data = {
one: 'a' + (size+1),
two: 'b' + (size+1),
three: 'c' + (size+1)
}
maj[size] = data;
console.clear();
console.log(maj);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="btnSubmitRejetRefModele">Add</button>
If you need an alternative, here's my original answer, which is using an array of objects, you can use it later as maj[0], maj[1], and so on:
$(document).ready(function() {
var maj = [];
$("#btnSubmitRejetRefModele").click(function() {
var data = {
one: 'a',
two: 'b',
three: 'c'
}
maj.push(data);
console.clear();
console.log(maj);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="btnSubmitRejetRefModele">Add</button>
This is not exactly the format you need, but maybe helps.
An alternative could be storing it in an array.
let data = {
myArray: [{'one':'a','two':'b','three':'b'}]
}
Then every time you can just add data by adding to that array.
data.myArray.push({'one':'a2','two':'b2','three':'b2'})
Advantage, no need to keep track of any counter variables.
Disadvantage, removing things from the array might be less performant or less convenient. But that depends on the use case.
Readability is the most important thing when writing code you want to maintain.
You should keep track of button clicks count, and use it when creating the new part of your JSON object.
var maj = {};
var counter = 0;
$("#btnSubmitRejetRefModele").click(function() {
var temp = {}
temp['one'] = aNewValue
temp['two'] = bNewValue
temp['three'] = cNewValue
maj[counter++] = temp
}
but finally, I recommend you to use an array instead of an object(it's already indexed)
just push your new created objects in it and whenever you wanted to convert it to an object, do this:
myObject = Object.assign({}, maj);

How to put data into multi dimensional array in js inside the loop

How can we put data into multi dimensional array or json within a loop.
I know that it's possible to store multi dimensional data at one time, but I want it inside the loop as I have described in the code.
var sub_cat_checked_val = [];
sub_cat_checked.each(function (index) {
var sub_cat_id = jQuery(this).attr('name').replace('subcategory_id_', '').replace('[]', '');
sub_cat_checked_val['key_one']['key_two']='value';
sub_cat_checked_val[sub_cat_id][index] = index:jQuery(this).val();
});
As it's possible in php like $var_name['key1']['key2']['keyn']='value';
sub_cat_checked_val[sub_cat_id] needs to be defined as an array, so add the lines:
if (!sub_cat_checked_val[sub_cat_id]) {
sub_cat_checked_val[sub_cat_id] = [];
}
to define the value as an array if it does not exist.
Try this snippet:
<script>
var k = {};
k.a = {};
k.a.b = {};
k.a.b.c = {};
k.a.b.c.d = 5;
console.log(k);
</script>
I was able to do it with all of you guys help with some of modifications.
Here is what I did:
sub_cat_checked.each(function (index) {
console.log(index_val);
var sub_cat_id = jQuery(this).attr('name').replace('subcategory_id_', '').replace('[]', '');
console.log(sub_cat_id);
if (sub_cat_checked_val[sub_cat_id] == undefined) {
sub_cat_checked_val[sub_cat_id] = [];
}
sub_cat_checked_val[sub_cat_id][index] = jQuery(this).val();
});
Thanks a lot to all of you.

Javascript: forEach() loop to populate an array - closure issue

Let's say we have an array of objects like:
var fruits = [ {name:"banana", weight:150},{name:"apple", weight:95},{name:"orange", weight:160},{name:"kiwi", weight:80} ];
I want to populate a "heavy_fruits" array with items from the "fruits" array above which weight is > 100. Here is my code:
var heavy_fruits = [];
myfruit = {};
fruits.forEach(function(item,index) {
if ( item.weight > 100 ) {
myfruit ["name"] = item.name;
myfruit ["weight"] = item.weight;
}
heavy_fruits.push(myfruit);
});
However it shows:
name:"orange", weight:160
name:"orange", weight:160
name:"orange", weight:160
name:"orange", weight:160
I know this is an issue with mixing closures and loops... but I read an article (http://zsoltfabok.com/blog/2012/08/javascript-foreach/) explaining that I would avoid this kind of issue using a forEach loop instead of the classic for loop.
I know I can use array methods like filter(), etc. but I'm asking that on purpose since I'm actually having troubles with a much bigger function that I cannot expose here... So I tried to summarize and simplify my issue description with "fruits".
var heavy_fruits = [];
myfruit = {}; // here's your object
fruits.forEach(function(item,index) {
if ( item.weight > 100 ) {
myfruit ["name"] = item.name;
myfruit ["weight"] = item.weight; // you modify it's properties
}
heavy_fruits.push(myfruit); // you push it to the array
});
You end up with an array [myfruit, myfruit, myfruit, myfruit].
Now if you modify myfruit anywhere in the code, the change will be visible in every single occurence of myfruit. Why?
Because you are modifying the referenece to the object.
In this example, your array stores just copies of your object. And if you change one of it, every single one will change, because they are all references.
To fix this with each iteration you should be creating a new object and then doing some stuff on it.
BTW, as a matter of fact, your if could just be like this:
if ( item.weight > 100 ) {
heavy_fruits.push(item); // if `item` only has `name` and `weight` properties
}
fruits.forEach(function (item, index) {
if (item.weight > 100) {
myfruit = {};
myfruit["name"] = item.name;
myfruit["weight"] = item.weight;
heavy_fruits.push(myfruit);
}
});
The shorter would use filter
var heavy_fruits = fruits.filter(x => x.weight > 100);
But if you realy want to use forEach do this way
var heavy_fruits = [];
fruits.forEach(x => {if(x.weight > 100) heavy_fruits.push(x)} );

remove items from array with the same id one by one

the problem is that I have multiple objects with the same id. As you can see this works when it comes to removing all the items with the same id. How I can remove the objects one by one no matter if they are the same ID...thanks
individualObjects:[],
actions:{
increment:function(){
var obj = this.get('object');
this.get('individualObjects').pushObject(obj);
},
decrement:function(){
var obj = this.get('object');
var filter = this.get('individualObjects').findBy('obj_id', obj.get('obj_id'));
this.get('individualObjects').removeObject(filter);
}
}
Well to filter array you would need to use Array.filter to find out the items that do not belong in the "individualObjects" and later simply remove them by using "removeObjects"
decrement:function(){
var objects = this.get('individualObjects')
var notWanted = objects.filterBy('obj_id', this.get('object.obj_id'));
this.get('individualObjects').removeObjects(notWanted);
}
and solution 2
decrement:function(){
var removeObj = this.get('object');
var objects = this.get('individualObjects')
// As the condition is true given object is returned
var notWanted = objects.filter(obj => { return obj.get('obj_id') === removeObj.get('obj_id')  });
this.get('individualObjects').removeObjects(notWanted);
}
Ok so you want to remove items one by one. Weird but can be accomplished
first get the length for
var notWantedCount = objects.filterBy('obj_id', this.get('object.obj_id')).length;
Now
for(var i=0; i <= notWantedCount; i++) {
var toRemove = individualObjects.findBy('obj_id', obj.get('obj_id'));
individualObjects.removeObject(toRemove);
// Make some custom actions one by one.
}
I don't know ember, but you'll want to do a foreach on the array, and then test for id on each one. It should be something like this:
decrement:function(){
var obj = this.get('object');
self = this;
this.get('individualObjects').each(function(individualObject) {
if (individualObject.get('obj_id') == obj.get('obj_id'))
... you want to do something here? ...
self.get('individualObjects').removeObject(individualObject);
}
}
That way you can remove each object individually. Running any necessary code before or after it's removed. If you want to sort it first, you can do that before running the each function.

Which is faster for finding element in javascript array?

I'm a noob and wrote a whole program without knowing the easy way to find an element in an array...
my_array.indexOf("find this value");
Is indexOf a lot better than storing how many elements are in an array, and looping through the array until you find the element you want? I could have simplified my code alot.
I tried to make my lookups constant time by using multiple arrays, and storing the keys. It makes insertions/deletes slow because I have to update the keys though.
Should I have just used indexOf?
Thanks
The vast majority of the time you are much better off to use a native function that has been optimized over whatever solution you come up with. Aside from that, however, you said something about storing the amount of elements in the array. Not sure why you did that when arrays have a .length property.
Javascript basically has two types of collections: Arrays and hashmaps. Both are a bit special. The hash map is just an object with named properties. The keys are strings that you use to access the values directly. Here's an example:
// create the hash map
var hashMap = {};
// add a value
var key = "John Dillinger";
hashMap[key] = "Criminal";
// retrieve the value
var stuff = hashMap[key];
Javascript arrays have a double functionality. They are of course arrays, but are also stacks. A stack follows the "last in - first out" rule. Here's an example of an array and a stack:
// Array example
var anArray = []; // or: var anArray = new Array();
anArray[0] = "some value";
alert(anArray[0]); // pops up "some value"
// Stack example
var stack = [];
stack.push("first");
stack.push("second");
alert(stack.pop()); // pop up "second"
Finally, for some problems a linked list could come in handy. For that you use an object. Something like this:
var linkedList = {value: "stuff"};
linkedList.next = {value: "other"};
linkedList.next.next = {value: "yet another value"};
// Traverse the list
var node = linkedList;
while(node) {
alert(node.value)
node = node.next;
}
Given the problem that you describe, I would use a hash map. Just remember to choose the correct collection type for any given problem.
You could use a hash table implementation in javascript to map values to array indices.
Native functions should be faster since it would be the runtime-engine precompiled code.
However, indexOf wasn't implemented until version 1.6, meaning it doesn't work in jscript/IE afaik.
But I would just prototype a workaround for it in that case. native functions is usually your best option.
In your case however, it seems that you want a hashmap, which in js is just a regular object as Helgi pointed out.
It's probable that the implementation of the indexOf method just loops over the array until it finds the requested value because in the general case that's about all you can do. Using it would clean up your code but is unlikely to make it faster. (There are faster ways of searching arrays but they carry certain restrictions and/or up-front costs.)
You should use the right data structure for the job. Arrays are for situations where order is important. If you find yourself searching through them a lot you should probably be using a hash instead. Hashes are unordered but lookups happen in constant time (no searching).
I've implemented javascript HashMap which code can be obtained from http://github.com/lambder/HashMapJS/tree/master
Here is the code:
/*
=====================================================================
#license MIT
#author Lambder
#copyright 2009 Lambder.
#end
=====================================================================
*/
var HashMap = function() {
this.initialize();
}
HashMap.prototype = {
hashkey_prefix: "<#HashMapHashkeyPerfix>",
hashcode_field: "<#HashMapHashkeyPerfix>",
initialize: function() {
this.backing_hash = {};
this.code = 0;
},
/*
maps value to key returning previous assocciation
*/
put: function(key, value) {
var prev;
if (key && value) {
var hashCode = key[this.hashcode_field];
if (hashCode) {
prev = this.backing_hash[hashCode];
} else {
this.code += 1;
hashCode = this.hashkey_prefix + this.code;
key[this.hashcode_field] = hashCode;
}
this.backing_hash[hashCode] = value;
}
return prev;
},
/*
returns value associated with given key
*/
get: function(key) {
var value;
if (key) {
var hashCode = key[this.hashcode_field];
if (hashCode) {
value = this.backing_hash[hashCode];
}
}
return value;
},
/*
deletes association by given key.
Returns true if the assocciation existed, false otherwise
*/
del: function(key) {
var success = false;
if (key) {
var hashCode = key[this.hashcode_field];
if (hashCode) {
var prev = this.backing_hash[hashCode];
this.backing_hash[hashCode] = undefined;
if(prev !== undefined)
success = true;
}
}
return success;
}
}
//// Usage
// creation
var my_map = new HashMap();
// insertion
var a_key = {};
var a_value = {struct: "structA"};
var b_key = {};
var b_value = {struct: "structB"};
var c_key = {};
var c_value = {struct: "structC"};
my_map.put(a_key, a_value);
my_map.put(b_key, b_value);
var prev_b = my_map.put(b_key, c_value);
// retrieval
if(my_map.get(a_key) !== a_value){
throw("fail1")
}
if(my_map.get(b_key) !== c_value){
throw("fail2")
}
if(prev_b !== b_value){
throw("fail3")
}
// deletion
var a_existed = my_map.del(a_key);
var c_existed = my_map.del(c_key);
var a2_existed = my_map.del(a_key);
if(a_existed !== true){
throw("fail4")
}
if(c_existed !== false){
throw("fail5")
}
if(a2_existed !== false){
throw("fail6")
}
Bon Appétit,
Lambder

Categories

Resources