String json has null values - javascript

I am trying to stringify my json -
for (var i = 0 ; i < lines.length ; i++) {
var label = lines[i];
var value = 1;
item = [];
item["label"] = label;
item["value"] = value;
jsonObj.push(item);
}
var jsonString = JSON.stringify(jsonObj);
During iteration, both label and value are being assigned accordingly with the correct values.
However jsonString is full of null values, why is this the case?

It should be item = {}; and not item = [];.
The first is the object literal, and the second is the array literal.
For good measure, do var items = {};

The case is that you create an array item = [] then set its string properties.
Whereas JSON.stringify expects that something that looks like an array is an array, so it does not even try to iterate over its non-numeric properties.
The solution for you would be to replace it with an object {}
The excerpt from the specification:
If Type(value) is Object, and IsCallable(value) is false
If the [[Class]] internal property of value is "Array" then
Return the result of calling the abstract operation JA with argument value.
followed by
Let len be the result of calling the [[Get]] internal method of value with argument "length".
Let index be 0.
Repeat while index < len
Let strP be the result of calling the abstract operation Str with arguments ToString(index) and value.
If strP is undefined
Append "null" to partial.
Else
Append strP to partial.
Increment index by 1.
References:
15.12.3 stringify
15.12.3 stringify JA

As pointed out, you'll need to make your item an object. Here's a JSFiddle to get you started with an example.
var item;
var lines = ["a","b","c"];
var jsonObj = {};
jsonObj.items = [];
for (var i = 0 ; i < lines.length ; i++) {
var label = lines[i];
var value = 1;
item = {};
item["label"] = label;
item["value"] = value;
jsonObj.items.push(item);
console.log(jsonObj);
}
var jsonString = JSON.stringify(jsonObj);
console.log(jsonString);

Related

Array.length gives incorrect length

If I have an array having object as values at the indices like:
var a = [];
a[21] = {};
a[90] = {};
a[13] = {};
alert(a.length); // outputs 91
I have found a workaround to get the actual length:
function getLength(arr) {
return Object.keys(arr).length;
}
var a = [];
a[21] = {};
a[90] = {};
a[13] = {};
alert(getLength(a));
But, why does JS gives incorrect length when objects are stored at random indices? It just adds 1 to the largest index found on an array. Like in the above example, 90 was the largest index. It just adds 1 and gives 91 as output. Demonstration
That's because length gives you the next index available in the array.
DOCS
arrayLength
If the only argument passed to the Array constructor is an integer between 0 and 2^32-1 (inclusive), this returns a new JavaScript array with length set to that number.
ECMA Specifications
Because you don't have inserted any element in the other keys than 21, 90, 13, all the remaining indexes contains undefined. DEMO
To get actual number of elements in the array:
var a = [];
a[21] = {};
a[90] = {};
a[13] = {};
var len = 0;
for (var i = 0; i < a.length; i++) {
if (a[i] !== undefined) {
len++;
}
}
document.write(len);
Shorter version
var a = [];
a[21] = {};
a[90] = {};
a[13] = {};
for (var i = 0, len = 0; i < a.length; i++, a[i] !== undefined && len++);
document.write(len);
DEMO
EDIT
If the array contains large number of elements, looping to get its length is not the best choice.
As you've mentioned in the question, Object.keys(arr).length is the best solution in this case, considering that you don't have any properties added on that array. Otherwise, the length will not be what you might be expecting.(Thanks To #RobG)
The array in JavaScript is a simple zero-based structure. The array.length returns the n + 1 where n is the maximum index in an array.
That's just how it works - when you assign 90'th element and this array's length is less than 90, it expands an array to 90 and sets the 90-th element's value. All missing values are interpreted as null.
If you try the following code:
var a = [];
a[21] = {};
a[90] = {};
a[13] = {};
console.log(JSON.stringify(a));
You will get the following JSON:
[null,null,null,null,null,null,null,null,null,null,null,null,null,{},null,null,null,null,null,null,null,{},null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,{}]
Moreover, array.length is not a readonly value.
If you set a length value less than the current, then the array will be resized:
var arr = [1,2,3,4,5];
arr.length = 3;
console.log(JSON.stringify(arr));
// [1,2,3]
If you set a length value more than the current, then the array will be expanded as well:
var arr = [1,2,3];
arr.length = 5;
console.log(JSON.stringify(arr));
// [1,2,3,null,null]
In case you need to assign such values, you can use JS objects.
You can use them as associative array and assign any key-value pairs.
var a = {};
a[21] = 'a';
a[90] = 'b';
a[13] = 'c';
a['stringkey'] = 'd';
a.stringparam = 'e'; // btw, a['stringkey'] and a.stringkey is the same
console.log(JSON.stringify(a));
// returns {"13":"c","21":"a","90":"b","stringkey":"d","stringparam":"e"}
console.log(Object.keys(a).length);
// returns 5
Because that's the behavior of Array.length as described in the ECMAScript spec.
The length property of this Array object is a data property whose value is always numerically greater than the name of every deletable property whose name is an array index.
So Array.length is always the last item's index + 1.
It's because you have a[90] as largest index so the index is starting from 0 to 90 becomes 91 in length.
And where you didn't pass the values like a[80], etc. javascript will store them as hole i.e. for eg [1, , 3, , ,90] where commas are used indicates the hole in array.
If you try to access those values then you'll get undefined.

Combine object value

My jquery array is showing like
[Object { qty=1, item_id="76", add_ons="2", add_on_price:20}, Object { qty=1, item_id="76", add_ons="1",add_on_price:40}]
I want to make an array like this
[object{ qty=2,item_id=76,add_ons_price=60}]
I need to add the qty,add_ons_price in single object.
any help will be appreciated.
this will group objects based on property item_id
var result = {};
for (var i = 0, len = myObjects.length; i < len; i++) {
var obj = myObjects[i];
if (result[obj.item_id] === undefined) {
result[obj.item_id] = [];
}
result[obj.item_id].push(obj);
}
now you can add the required values and push the result in new object

Loop through and compare javascript objects

I have two arrays which are created from the inputs of a user like so:
var impArray = [];
$('[id^=imp]').on('change', function(){
var value = $(this).val();
var name = ($(this).attr('name').replace('imp-',''))
impArray[name] = value;
console.log(impArray);
})
var assessArray= [];
$('[id^=assess]').on('change', function(){
var value = $(this).val();
var name = ($(this).attr('name').replace('assess-',''))
assessArray[name] = value;
console.log(assessArray);
})
These create arrays like
assessAray
1-1: 10
1-2: 15
1-3: 9
impArray
1-1: 6
1-2: 14
1-3: 2
I then need to do a simple calculation with the matching keys like:
$('#comp-1-1').val(impArray['1-1'] / assessArray['1-1'] * 100);
Obviously I can't do this with every single one, so,
Question: How can I loop through the arrays and compare them based on keys then do something with their values?
Technically, you are working with JavaScript objects, not arrays. Your variable declarations should actually be:
var impArray = {};
var assessArray = {};
Once you have the correct variable declarations, you can use jQuery.each to iterate through keys (not indexes):
$.each(impArray, function(key, value){
$('#comp-'+key).val(assessArray[key]/value*100);
});
Try using $.each(), like:
$.each(impArray, function(i, v){
$('#comp-'+i).val(v/assessArray[i]*100);
});
Does this help you?
$.each(impArray, function(index, value){
var result = assessArray[index] / value * 100;
$('#comp-1-'+index).val(result);
});
If both arrays will always be the same length and have the object property at the same index, this should work:
http://jsfiddle.net/9DBuD/
assessArray = [{'1-1':'10'},{'1-2':'15'},{'1-3':'9'}];
impArray = [{'1-1':'6'},{'1-2':'14'},{'1-3':'2'}];
for(var i=0;i<assessArray.length;i++){
for(var prop in assessArray[i]){
for(var property in impArray[i]){
if(prop == property){
$('#comp-'+prop).val(impArray[i][property]/assessArray[i][prop]*100)
}
}
}
}
Edit
This modified fiddle and code should produce the same results even if the array indexes and sizes do not match:
http://jsfiddle.net/9DBuD/1/
Array.prototype.indexOfProp = function (property) {
for (var i = 0, len = this.length; i < len; i++) {
if (this[i][property]!=undefined) return i;
}
return -1;
}
assessArray = [{'1-2':'15'},{'1-3':'9'},{'1-1':'10'},{'1-4':'10'}];
impArray = [{'1-1':'6'},{'1-3':'2'},{'1-2':'14'}];
for(var i=0;i<assessArray.length;i++){
for(var prop in assessArray[i]){
var index = impArray.indexOfProp(prop)
if(index!=-1){
$('#comp-'+prop).val(impArray[index][prop]/assessArray[i][prop]*100)
}
}
}

Add values to an array

How to add values to an empty array? I have tried the following but it is not working:
var student = [{}];
for (var i = 0; i < 5; i++) {
student[i].name = i;
student[i].id = "1";
student.push(student[i]);
}
var a = JSON.stringify(student);
alert(a);
It give output 6 time repeated last values not 5 time :
'[{"name":4,"id":"1"},{"name":4,"id":"1"},{"name":4,"id":"1"},{"name":4,"id":"1"},{"name":4,"id":"1"},{"name":4,"id":"1"}]'
var student = [{}];
This creates a javascript array containing one empty object
student[i].name = i;
student[i].id = "1";
For i = 0, this alters that empty object.
student.push(student[i]);
You then push that altered object to the array it already exists in. You now have two identical values in the array.
Two items after first push. This is repeated five times.
Pushing an item adds it to the array. There's usually no point in pushing an element that's already in the array. Create a new object and push that. The array doesn't have to be pre-populated with an empty object to modify.
var student = [];
for (var i = 0; i < 5; i++) {
student.push({
name: i,
id: '1'
});
}
In your original code, you are setting the object at student[i]'s values, then just pushing it again onto the array, then setting those values all over again.
You need to push a new object each time:
var student = [];
for (var i = 0; i < 5; i++) {
student.push({
id: i,
name: i
});
}
var a = JSON.stringify(student);
alert(a);
You are using the same name for the list and the new object. When you change the name of the list to students, your problem is fixed. Solution below:
var students = [{}];
for (var i = 0; i < 5; i++) {
student = {}
student.name = i;
student.id = "1";
students.push(student);
}
var a = JSON.stringify(students);
alert(a);
try ;
var students = [];
for (var i = 0; i < 5; i++) {
student = {}
student.name = i;
student.id = "1";
students.push(student);
}
var a = JSON.stringify(students);
alert(a);
Your array is not empty. It already contains an object. Maybe the problem is easier to see if we put the object in an extra variable and omit the the loop:
var student = [];
var obj = {};
obj.name = 1;
student.push(obj);
obj.name = 2;
student.push(obj)
The question is: How many objects are we creating here? The answer is one, namely var obj = {};. We then add some properties to the object (name) and add it to the array (student.push(obj)).
What comes next is crucial: We change the existing properties of the object and assign different values to it. Then we add the object to the array again. Even though student contains two elements, but they refer to the same value (which can be easily verified with student[0] === student[1]).
If you want to create an array of different objects, you have to create those objects. In our example this would be:
var student = [];
var obj = {};
obj.name = 1;
student.push(obj);
obj = {}; // <- create a new object
obj.name = 2;
student.push(obj)
For your code that means that you have to create a new object in each iteration of the loop, not just one outside of it.
Reading material about arrays and objects:
Eloquent JavaScript - Data structures: Objects and Arrays
MDN - Working with objects
MDN - Array object
Since you are pushing object, its reference change every time to current value so at last it shows the output as last value.
Try this
var student = [{}];
for (var i = 0; i < 5; i++) {
var obj = new Object();
obj.name = i;
obj.id = "1";
student.push(students);
}
var a = JSON.stringify(student);
alert(a);

how would I go about accessing a deep value using a single variable in bracket notation?

I am wondering how to do the following- I have the following data:
dta = {
"fielddata": {
"text1": "4B030C2E-3D53-4DF8-A3535EF377B45DE5",
"text2": "Unlabeled"
}
}
Which I can access using bracket notation like so
var result = dta["fielddata"]["text1"];
no problem there, And I can use variables like so
var val1 = "fielddata",
val2 = "text1",
acc = dta[val1][val2];
log(acc);
again, terrific- but how about when I only have a single variable holding the dot notation?
like, what if I only have
var val = "fielddata.text1",
acc = dta[val];
log(acc);
This would yield an undefined.
Any thoughts on how to go about this?
Thanks alot!
Marco
var val = "fielddata.text1",
acc = dta, // reference the base object
parts = val.split('.'), // split the val into an Array of individual parts
i;
// Iterate the parts, updating acc each time
for( i = 0; i < parts.length; i++ )
acc = acc[parts[i]];
Another option is JSONPath. For relatively simple usecases, doing it manually is likely a better solution, but with greater complexity, I might use something more formalized.
And while I hate to suggest it, there's always eval('dta.fielddata.text1')
getter
exports.getDeep = function(field, object){
var parts = field.split('.');
var value = object;
// Iterate the parts, updating value each time
for( var i = 0; i < parts.length; i++ ){
value = value[parts[i]];
if(i==parts.length-1){
return JSON.parse(JSON.stringify(value))
}
}
}
setter
exports.setDeep = function(field, object, newvalue){
var parts = field.split('.');
for( var i = 0; i < parts.length; i++ ){
if(i==parts.length-1){
object[parts[i]] = newvalue
return object
}
}
}

Categories