Insert values in to an object from loop - javascript

I'm trying to create a script that will insert some values in to an object.
I basically want to end up with a series of objects that would look something like this -
myObj.data.person[0].name = 'name 1';
myObj.data.person[1].name = 'name 2';
myObj.data.person[2].name = 'name 3';
etc
Here is my object which contains an array of objects.
var addressBook = {
data: [
person = {
name: '',
address: ''
}
]
}
And a for loop to insert repeating information.
for (i=0; i < 10; i++)
{
myObj.data.person[i] = {name: 'Joe Bloggs', address: 'Main Street'};
console.log(myObj.data.person.name);
}
Whenever I run this code I get the following error -
Uncaught TypeError: Cannot set property 'person' of undefined at <anonymous>:14:24
So, the question is where am I going wrong ? And furthermore would this be considered the right way to go about creating a list of Objects (e.g. Person 1, Person 2 etc)?
(I'm ultimately thinking of how I can create something like a Person constructor and use a loop to create multiple Person objects).
Thanks,

Please try to change your object notation in following way
var addressBook = {
data: [{
name: '',
address: ''
},
{
name: 'Roshan',
address: ''
},
{
name: 'Roshan1',
address: ''
}
]
}

try this :
myObj.data[i].person = 'John';
myObj.data[i].address = 'NYC';

See this Answer as addendum to isetty ravitejakumar's Answer
You should consider writing a prototype / class for your usecase.
In this case you could keep better track of your data.
maybe something like this:
var AddressBook = {},
Person = {};
(function() {
AddressBook.prototype = {
data: [],
add: function(person) {
this.data.push(person);
}
};
Person = function(name, address) {
this.name = name;
this.address = address;
}
Person.prototype = {
name,
address
};
})();

Related

Vue computed property changes the data object

I have basically this structure for my data (this.terms):
{
name: 'First Category',
posts: [
{
name: 'Jim James',
tags: [
'nice', 'friendly'
]
},
{
name: 'Bob Ross',
tags: [
'nice', 'talkative'
]
}
]
},
{
name: 'Second Category',
posts: [
{
name: 'Snake Pliskin',
tags: [
'mean', 'hungry'
]
},
{
name: 'Hugo Weaving',
tags: [
'mean', 'angry'
]
}
]
}
I then output computed results so people can filter this.terms by tags.
computed: {
filteredTerms: function() {
let self = this;
let terms = this.terms; // copy original data to new var
if(this.search.tags) {
return terms.filter((term) => {
let updated_term = {}; // copy term to new empty object: This doesn't actually help or fix the problem, but I left it here to show what I've tried.
updated_term = term;
let updated_posts = term.posts.filter((post) => {
if (post.tags.includes(self.search.tags)) {
return post;
}
});
if (updated_posts.length) {
updated_term.posts = updated_posts; // now this.terms is changed even though I'm filtering a copy of it
return updated_term;
}
});
} else {
return this.terms; // should return the original, unmanipulated data
}
}
},
filteredTerms() returns categories with only the matching posts inside it. So a search for "angry" returns just "Second Category" with just "Hugo Weaving" listed.
The problem is, running the computed function changes Second Category in this.terms instead of just in the copy of it (terms) in that function. It no longer contains Snake Pliskin. I've narrowed it down to updated_term.posts = updated_posts. That line seems to also change this.terms. The only thing that I can do is reset the entire data object and start over. This is less than ideal, because it would be loading stuff all the time. I need this.terms to load initially, and remain untouched so I can revert to it after someone clears their search criterea.
I've tried using lodash versions of filter and includes (though I didn't really expect that to make a difference). I've tried using a more complicated way with for loops and .push() instead of filters.
What am I missing? Thanks for taking the time to look at this.
Try to clone the object not to reference it, you should do something like :
let terms = [];
Object.assign(terms,this.terms);
let terms = this.terms;
This does not copy an array, it just holds a reference to this.terms. The reason is because JS objects and arrays are reference types. This is a helpful video: https://www.youtube.com/watch?v=9ooYYRLdg_g
Anyways, copy the array using this.terms.slice(). If it's an object, you can use {...this.terms}.
I updated my compute function with this:
let terms = [];
for (let i = 0; i < this.terms.length; i++) {
const term = this.copyObj(this.terms[i]);
terms.push(term);
}
and made a method (this.copyObj()) so I can use it elsewhere. It looks like this:
copyObj: function (src) {
return Object.assign({}, src);
}

Turf JS does not create Object properly

I am using the helper function turf.point()
const feature = turfHelpers.point(coords, properties, { id: properties.id });
properties looks like this
properties = {
id: 1,
thisWorks: 'no problem'
foo: {
thisDoesntWork: 'this is a problem'
}
}
When I create feature with turfHelpers.point(), it messes with the object. The nested object is not an object anymore, but gets stringyfied...
So, features.properties is
{
id: 1,
thisWorks: 'no problem'
foo: "{
thisDoesntWork: 'this is a problem'
}"
}
Now, I cannot access. feature.properties.foo.thisDoesntWork anymore, because its a string...
Why is turf.js doing that?
Let's put the question in the runnable form.
const turfHelpers = turf.helpers;
const coords = [100, 14];
const properties = {
id: 1,
thisWorks: 'no problem',
foo: {
thisDoesntWork: 'this is a problem'
}
};
var feature1 = turfHelpers.point(coords, properties, {
id: properties.id
});
// Print out on console
console.log(feature1.properties); //look OK
console.log(feature1.properties.foo); //also OK
console.log(feature1.properties.foo.thisDoesntWork); //also OK
<script src="https://cdnjs.cloudflare.com/ajax/libs/Turf.js/5.1.5/turf.min.js"></script>
Then, hopefully, it is helpful for discussion that leads to a solution.

How to get proprety value of object from parent object

I have object in this structure:
obj = {
user: { name: 'jeterson' },
title: 'I am a test'
}
I have one key with value: user.name.
I have trying get value like this: obj[key], meaning obj['user.name']. It not works, only works for obj.title.
My object have many values that are also objects, and i want get value like this:
myobject[mykey]
It is possible get value from property object like above ?
You can access it with:
obj['user']['name']
Or alternatively:
obj.user.name
If you want to get from a key like "user.name" to the value, you woulr have to do some logic yourself. You could hack something together like this:
let obj = {
user: {
name: 'jeterson'
},
title: 'I am a test'
}
let key = 'user.name';
let keys = key.split('.');
let res = obj;
while (keys.length > 0 && res) {
let k = keys.shift();
res = res[k];
}
console.log(res) // "jeterson"
When the keys do not match, res holds undefined.
You've got multiple solutions to access an element of an object with its keys:
var obj = {
user: { name: 'jeterson' },
title: 'I am a test'
}
console.log(obj['user']['name']);
console.log(obj['user'].name);
console.log(obj.user['name']);
console.log(obj.user.name);
But you can't do it easily with a variable key = 'user.name'.
If you need to use a variable containing the nested-keys, you could create a function.
Updated answer: An amazingly short way to achieve it is to use .reduce():
// My function
function obj_tree_key(obj, path) {
return path.split('.').reduce((accu, val) => accu[val] || 'Not found', obj);
}
var obj1 = {
user: {
name: 'jeterson'
},
title: 'I am a test'
}
console.log(obj_tree_key(obj1, 'user.name')); // Outputs "jeterson"
// Here is an example with error:
var obj2 = {
user: {
nameeeee: 'jeterson'
},
title: 'I am a test'
}
console.log(obj_tree_key(obj2, 'user.name'));
Old answer: Use a for to loop through the keys and reduce the oject:
// My function
function obj_tree_key(obj, tree_key) {
var result = obj;
var keys = tree_key.split('.');
for (var i = 0; i < keys.length; i++) {
result = result[keys[i]] || 'Not found'; // Error handling
}
return result;
}
var obj1 = {
user: {
name: 'jeterson'
},
title: 'I am a test'
}
console.log(obj_tree_key(obj1, 'user.name')); // Outputs "jeterson"
// Here is an example with error:
var obj2 = {
user: {
nameeeee: 'jeterson'
},
title: 'I am a test'
}
console.log(obj_tree_key(obj2, 'user.name'));
Hope it helps.
first get the user, then the name:
obj['user']['name']
or
obj.user.name
You can also use
obj.user.name
You could access it using
console.log(obj.user.name);
You can do it in 2 way:
obj['user']['name']
or
obj.user.name

How to find values from another JSON object

I have set of json objects.
Languages
User Details
User Details have the languages field - which have more than 1 values.
Here is my sample json
$scope.languages = [
{id: 1, text: 'English'},
{id: 2, text: 'French'},
{id: 3, text: 'Hindi'},
{id: 4, text: 'Telugu'}
];
$scope.users = [{name: 'first user', status: 1,language:"1"},
{name: 'second user', status: 2,language:"1,2"},
{name: 'third user', status: 3,language:"1,3,4"}];
In my view i want to list the user name and languages.
<li ng-repeat="user in users">{{user.name}} - {{testString}}</li>
I know to do for single value. But for multiple values. I have the logic but i don't know how to implement. I am thinking that. First i have to split the user language string and change into array and then find the index of the language id and then return the language text.
I have the code to return language name from ID.
var foundItem = $filter('filter')($scope.languages, { id: 3 }, true)[0];
var index = $scope.languages.indexOf(foundItem );
$scope.result = $scope.languages[index].text;
So now the problem is how to print the languages next to the user name?
I tried like this
$scope.testString = function() {
return "return test string";
}
{{testString}}
But its not working. If this works we can pass the langugae codes as parameter and i can add the search code inside the testString function.
Thanks
testString is a function so you cannot use it like {{testString}}, you have to call that function {{testString()}}
You can simplify your code like this.
$scope.getLanguages = function (langs) {
var l = [];
angular.forEach(langs.split(','), function (lang) {
l.push(findLanguageTextById(parseInt(lang)));
})
return l.join(', ');
}
function findLanguageTextById (langId) {
for(var i = 0;i<$scope.languages.length;i++) {
if ($scope.languages[i].id == langId) {
return $scope.languages[i].text;
}
}
}
I have created a working demo for your problem take a look.
http://plnkr.co/edit/Cdl8y58IExoVSZV6lp76?p=preview
I think you are not calling the function,
$scope.testString = (function() {
return "return test string";
})();

Check if property is not undefined

I'm building a node+express app and I'm filling an object with JSON that's submitted from a form in the frontend. This works, unless I leave a field empty in the form so that e.g. req.body.address.street is empty/undefined.
This will result in the error:
TypeError: Cannot read property 'street' of undefined
var b = new Business({
name: req.body.name,
phone: req.body.phone,
address: {
street: req.body.address.street,
postalCode: req.body.address.postalCode,
city: req.body.address.city
},
owner: {
email: req.body.owner.email,
password: req.body.owner.password
}
});
My question is how I can best prevent my app from crashing when values are empty. I would like to avoid manually checking each and every property in my app against undefined.
I'm wondering what the best practice is for this common issue.
I don't know if you use jQuery in your project, but if you do, you can create a mask:
// creating your object mask
var req = {
body: {
name: '',
phone: '',
address: {
street: '',
postalCode: '',
city: ''
},
owner: {
email: '',
password: ''
}
}
}
And then, you simply use the jQuery "extend" method (req2 is your submmited object):
$.extend(true, req, req2);
I've create this fiddle for you!
-
Update
Nothing related to your question, but I've just noticed that you're passing an object with a similar structure of req.body to the Business class. However, there is no need to copy property by property manually - you can make, for example, a simple copy of req.body to pass as parameter:
var b = new Business($.extend({}, req.body));
or
var b = new Business(JSON.parse(JSON.stringify(req.body)));
You can't, really. You have two options;
Use a try/ catch:
try {
var b = new Business({
//
});
} catch (e) {
// Something wasn't provided.
}
... or you can define a helper function:
function get(path, obj) {
path = path.split('.');
path.shift(); // Remove "req".
while (path.length && obj.hasOwnProperty(path[0])) {
obj = obj[path.shift()];
}
return !path.length ? obj : null;
}
... you could then replace your use of req.body.address.street etc. with get('req.body.address.street', req).
See a demo here; http://jsfiddle.net/W8YaB/

Categories