Populate JSON with javascript array and modify entry - javascript

Modifying a JSON array (nested into another array) seems NOK with this code:
var names = [{'name': 'ourname'},{'name': 'yourname'}] ;
var array = [{
"year": "2015",
names
},{
"year": "2016",
names
}];
I can't modify a single name entry in "array" by doing this
array[0].names[1].name="MY NAME"
since it's actually modifying all names entry in the row "0":
Output:
0:0 ourname
0:1 MY NAME
1:0 ourname
1:1 MY NAME
Plunker here
I'm looking for a clean way to achieve a proper single modification in the name array as I'd like to avoid loops to do this.
Thanks for your help

Because they're pointing to same array, and also, simply clone names by .slice is not enough, as the array contains objects not primitive types, so you need to deep clone from the original names and assign to each object.
So you need to change the code to :
var array = [{
"year": "2015",
names: JSON.parse(JSON.stringify(names))
}, {
"year": "2016",
names: JSON.parse(JSON.stringify(names))
}];
See the edited pluker.
I use JSON.parse(JSON.stringify(names)) to simply create do deep clone from original array here, there can have other ways.

You should try copying the names array, once for each "unique" use case, since Javascript sneakily has references sometimes.
One way to do it is to write a deepclone() method that will do a deep copy of a hierarchical object.
var array = [{
"year": "2015",
names: deepclone(names)
},{
"year": "2016",
names: deepclone(names)
}];

You need a key: value in an object (javascript object).
var names = [{'name': 'ourname'},{'name': 'yourname'}] ;
var array = [{
"year": "2015",
"names": names
},{
"year": "2016",
"names": names
}];
var wName = array[0].names[1].name;
// yourname

Related

Get info from Array then Object in Javascript

I'm trying to display data after a Fetch. I grouped this data by date so I grouped my objects into an array which have the date as main key.
But now, I'm kind of lost and don't know how to display get the date as Header section then the objects.
This is my data:
"31 janvier 2015": Array [
Object {
"image": "image",
"name": "name",
},
Object {
"image": "image",
"name": "name",
},
],
"02 février 2016": Array [
Object {
"image": "image",
"name": "name",
},
Object {
"image": "image",
"name": "name",
},
]
What I would like to do is to display it like a section list :
31 janvier 2015
> object
> object
02 février 2016
> object
> object
I think I can map the objects but first I have to get the date and go inside that array.
What you have is an associative array, that is an array that instead of numeric indexes has strings. It works just like an object would if you were for example to do person['age'] on a person object.
You can loop through the "indexes" with the below code, checking hasOwnProperty to avoid any inherited properties. You can then access your dates by key
for (var key in MainArray) {
if (MainArray.hasOwnProperty(key))
console.log(MainArray[key]);
}
Iterate over the map keys, displaying the date and listing the items.
for(let date in list){
// Date as SECTION HEADING
console.log(date);
// access items...
const items = list[date];
// Display item
items.forEach(console.log);
}

How to parse/filter data from JSON file in Javascript

Is there any way to parse/filter the data present in JSON file in a Javascript file.
Basically, I am calling JSON file into my local javascript. I am having trouble in reading specific data and printing.
Can anyone please help.
JSON file contains:
{
"Data": [
{
"name": "John",
"age": 30
},
{
"joined on":"Jan 2015",
"working on": "Automation",
}
]
}
I am trying to read the above JSON file as:
var jfile = require("./Example.json");
var test = JSON.parse(JSON.stringify(jfile))
console.log(test)
I get the output like this:
{ Data:
[ { name: 'John', age: 30 },
{ 'joined on': 'Jan 2015', 'working on': 'Automation' } ] }
From the above, I am interested in accessing/filtering out only one i.e. "name". I would like to print only the value "John" to the console.
I have tried to use the ".filter" method to the JSON.parse method but it throws me an error as:
JSON.parse(...).filter is not a function
Is there any way to perform this activity?
You can access it using . dot notation
var a = {
"Data": [{
"name": "John",
"age": 30
},
{
"joined on": "Jan 2015",
"working on": "Automation",
}
]
}
console.log(a.Data[0].name)
filter is an array method.
JSON.parse(...) will not give you an array. It will give you an object with a Data property. The value of that property is an array.
JSON.parse(...).Data.filter.
You can't just ignore parts of your data structure.
If you have multiple items in your array of different shapes, you can use this
Access the Data key with json.Data
map your array to transform its items into names
apply filter(Boolean) to take out those who are undefined
In your case you'll end up with an array containing only one name John
const getName = json => json.Data.map(x => x.name).filter(Boolean);
const json = {
"Data": [{
"name": "John",
"age": 30
},
{
"joined on": "Jan 2015",
"working on": "Automation",
}
]
};
console.log(getName(json));
Your JSON's main level is an object (not an array) and only arrays have .filter method.
So filter the array under Data key:
var test = JSON.parse(JSON.stringify(jfile)).Data.filter(/*something*/);
But better if you aren't re-parse JSON:
var test = jfile.Data.filter(/*something*/);
As Quentin mentioned in his comment, What is the use of below statement ?
var test = JSON.parse(JSON.stringify(jfile))
You can directly access the name property from the response.
Try this :
var obj = {
"Data": [{
"name": "John",
"age": 30
},
{
"joined on": "Jan 2015",
"working on": "Automation"
}
]
};
// Solution 1
console.log(obj.Data.map(item => item.name).filter(Boolean));
// Solution 2
console.log(obj.Data.filter(item => item.name).map(elem => elem.name));

Angular2 filter nested array of objects

I have an array of objects as below. I am trying to achieve search functionality using .filter() method in my angular2 application.
[{
"label": "new",
"result": [{
"label": "new",
"fname": "abc",
"lname": "xyz"
}, {
"label": "new",
"fname": "abc1",
"lname": "xyz1"
}]},
{
"label": "old",
"result": [{
"label": "old",
"fname": "abc2",
"lname": "xyz2"
}]
}]
I am able to achieve parent/one level filtering using below code:
this.data.filter(item => (item.label.toLowerCase().indexOf(inputText) !== -1);
This is returning the object that matches value of label. I want to have filter on 'fname' and 'lname' also.
Your data structure is not well suited for doing an arbitrary string lookup from a 3 level data structure like this.
Your are going to end up having to iterate all three levels - the array of objects, the results array in each object, and all the properties of the objects in the results array.
This is an O(n^3) operation and would likely perform unsatisfactorily with a large data set. You may need to think about how you can better structure this data for this use case.
I would when I get the data from the server create a lookup variable inside every item which contains all text you want to be able to search.
But make sure this is only done once, since it's wouldn't be very performant if you did it for every keystroke.
// Add searchable string to users
users.forEach(u => {
u.filterTerm = `${(u.id || '').toLowerCase()} ${(u.email || '').toLowerCase()} ${(u.firstName || '').toLowerCase()} ${(u.lastName || '').toLowerCase()}`;
});
Then you can use the includes method to filter
let filtered = allUsers.filter(u => {
return u.filterTerm.includes(filterTerm);
});

What is the correct format of populating a JSON object with a nested array of objects?

I'm trying to create a JSON object with a nested array of JSON objects. What is the correct format of this?
Here is an example what I am trying to create:
{
"reviewCount": 96,
"reviews": [
{"name": "Sean Steinman", "date": "reviewed 2 weeks ago", "reviewContent": "Fantastic Service"},
{"name": "Ryan Lundell", "date": "reviewed in the last week", "reviewContent":"Ask for Scott!"}
]
}
Here is what I have so far:
var reviewObj = {
reviewCount: reviews.length,
reviews: [{name: , date: , reviewContent:}]
}
After I initialize it, I will fill it with a for loop that runs through an existing array of strings.
CLARIFICATION:
The array that I'm using to populate the JSON object is:
[
"\nSean Steinman\nreviewed 2 weeks ago\n Fantastic Service\n",
"\nRyan Lundell\nreviewed in the last week\n Ask for Scott!\n• • •\n"
]
So I'm creating a new array in my for with tmpArr = reviews[i].split('/n');, and then where I'm getting stuck is how to stick that into the JSON object as an object.
First, you're not building a "JSON" object. You're just building an object. It's not JSON until you JSON-encode it. {"name": "bob"} is not JSON, it's an object literal. '{"name": "bob"}', the string, is JSON.
Second, you cannot loop inside an object literal, which is what your second code example seems to indicate you're trying to do. Instead, you need to initialize you reviews property to an empty array, and then loop and append items to the array.
var reviews = [
"\nSean Steinman\nreviewed 2 weeks ago\n Fantastic Service\n",
"\nRyan Lundell\nreviewed in the last week\n Ask for Scott!\n• • •\n"
];
var reviewObj = {
reviewCount: reviews.length,
reviews: []
}
reviews.forEach(function(line) {
var review = line.split("\n");
reviewObj.reviews.push({name: review[0], date: review[1], reviewContent: review[2]});
});

Does angularjs automatically create nested structures?

a bit confused about how to create and reference items in a nested array using angular.js. I was thinking that I could do:
$scope.zones = [ {z:'north'}, {z:'south'} ];
$scope.zones.times = [ {t:'noon'}, {t:'midnight'} ];
$scope.zones.times.places = [ {p:'here'}, {p:'there'} ];
and angularjs would create a structure in which every zone has two times and every time has two places.
Then I could use something like:
<ul ng-repeat="zone in $scope.zones">
<li>{{zone.z}}</li>
<ul ng-repeat="time in zone.times">
<li>{{time.t}}</li>
<ul ng-repeat="place in time.places">
<li>{{place.p}}</li>
</ul>
</ul>
</ul>
to see the tree structure on my page.
So, does using the dot notation above actually create a nested array of objects? Should I be able to reference them "recursively" as in the directive above? I'm having trouble getting this to work beyond the first two levels.
You're not setting up your data correctly. It should be:
$scope.zones = [ {z:'north'}, {z:'south'} ];
$scope.zones[0].times = [ {t:'noon'}, {t:'midnight'} ];
$scope.zones[1].times = [ {t:'noon'}, {t:'midnight'} ];
Etc...
Then your HTML should work as expected.
In JavaScript using obj.propName accesses the property named propName of the object referenced by obj.
Arrays are also objects (in JavaScript), so these lines of code:
$scope.zones = [...];
$scope.zones.times = [...];
create an array (named zones) and give it a property named times (which is also an array).
Note: This is JavaScript-specific and has nothing to do with Angular.
This is not what you want. You want to give the times property to zones' items, not to zones itself. (Similarly with places.)
In order to achieve that, you need to iterate over the elements of each array and give it the extra properties.
var places = [{p: 'here'}, {p: 'there'}];
var times = [{t: 'noon'}, {t: 'midnight'}];
var zones = [{z: 'north'}, {z: 'south'}];
// Give each `time` a `places` property
times.forEach(function (time) {
time.places = places;
});
// Give each `zone` a `times` property
// (Each `time` already has a `places` property.)
zones.forEach(function (zone) {
zone.times = times;
});
// Assign the augmented `zones` to `$scope.zones`
$scope.zones = zones;
See, also, this short demo.
Note:
In the above implementation, values are passed by reference. This means that is you change $scope.zones[0].times[0].places[0], $scope.zones[1].times[1].places[0] will also be affected, since it references the same object.
This implementation is OK if you just want to read values, as it's more efficient.
If you want to be able to also modify the objects, then you need to create copies of the objects and not assign them by reference.
E.g., instead of time.places = places; and zone.times = times;
write time.places = angular.copy(places); and zone.times = angular.copy(times); respectively.
The resulting $scope.zones object will look liek this:
[{
"z": "north",
"times": [{
"t": "noon",
"places": [
{"p": "here" },
{"p": "there"}
]
}, {
"t": "midnight",
"places": [
{"p": "here" },
{"p": "there"}
]
}]
}, {
"z": "south",
"times": [{
"t": "noon",
"places": [
{"p": "here" },
{"p": "there"}
]
}, {
"t": "midnight",
"places": [
{"p":"here" },
{"p":"there"}
]
}]
}]
Note:
In your HTML code you reference $scope.zones. This is an error !
The corect way is: zones
(All Angular expressions are evaluated in the context of the current Scope, thus ng-repeat="zone in $scope.zones" will look for $scope.$scope.zones.)

Categories