Property undefined halfway through Javascript array - javascript

I'm trying to compare each object in the two arrays in order to find matches. Currently, I am only comparing one property, but plan to compare two properties when I can get this part working.
I find it odd that it works for the first three items in the array and returns an error on the fourth. Here is the console output in Chrome:
Washington
Smith
yes
Jones
Uncaught TypeError: Cannot read property 'name' of undefined
Here is my javascript:
var self = this;
self.people = [
{ id: '1', name: 'Washington' },
{ id: '2', name: 'Smith' },
{ id: '1', name: 'Jones' },
{ id: '1', name: 'Smith' },
{ id: '3', name: 'Washington' }
];
self.params = [
{id: '1', name: 'Jones'},
{id: '2', name: 'Smith'}];
for (var value in self.params) {
for (var value in self.people) {
console.log(self.people[value].name);
if (self.people[value].name == self.params[value].name) {
console.log('yes');
}
}
}
If I remove the if statement, the code runs without error and prints the "names" in the people array twice as expected. Thoughts? Thanks in advance!

You're using twice the variable name "value".
Btw in Javascript the variables aren't scoped at block level (your 2 var declarations in the 2 for), but they're either global or function scoped.
I'm not sure what exactly you want to achieve, but maybe the next lines can give you a hint:
var val,
value;
for (val in self.params) {
for (value in self.people) {
console.log(self.people[value].name);
if (self.people[value].name == self.params[val].name) {
console.log('yes');
}
}
}

for (var value in self.params) {
for (var value1 in self.people) {
console.log(self.people[value1].name);
if (self.people[value1].name == self.params[value].name) {
console.log('yes');
}
}
}
You are using the same variable for both the loops...

Related

Find a Value in a Dictionary with a certain Property

Say I have a dictionary like
objDict = {
id1 : { name: 'someObj1', id: 'someId1' },
id2 : { name: 'someObj2', id: 'someId2' },
id3 : { name: 'someObj3', id: 'someId3' },
}
If I wanted to search for the property "someId2" of the "id" property in Values of that dictionary.. how would I be able to grab the the whole object after finding it?
I really can't think of a good way to do it outside of iterating the dictionary with a for-in loop. I was thinking of using Object.values() but even then I can't think of a way of using that to grab the whole object that contains someId2.. I would only be able to determine if that property existed.
I was just wondering if there was a better way than a for-in loop. Thanks
you can just get all the keys using Object.keys(), then iterate over these and select the object you want based on the required id.
var objDict = {
id1 : { name: 'someObj1', id: 'someId1' },
id2 : { name: 'someObj2', id: 'someId2' },
id3 : { name: 'someObj3', id: 'someId3' },
};
var obj;
Object.keys(objDict).forEach(x => obj = objDict[x].id === 'someId2' ? objDict[x]: obj);
console.log(obj);
There is Object.entries(), but for-in loop is more efficient than the other alternatives.
objDict = { id1 : { name: 'someObj1', id: 'someId1' },
id2 : { name: 'someObj2', id: 'someId2' },
id3 : { name: 'someObj3', id: 'someId3' } }
item = Object.entries(objDict).find(a => a[1].id === 'someId2')
console.log(JSON.stringify(item))
The following code snippet containing break; statement could statistically provide a better performance vs. the selected one.
objDict = {
id1 : { name: 'someObj1', id: 'someId1' },
id2 : { name: 'someObj2', id: 'someId2' },
id3 : { name: 'someObj3', id: 'someId3' },
};
var obj;
for (var key in objDict)
{
if (objDict[key].id==='someId2')
{
obj = objDict [key];
break;
}
}
console.log(obj);
ECMA Script 2015 provides another alternative of using Map object as described in : How to iterate (keys, values) in javascript?
Hope this may help.
This is a generic indexing problem, so no, there's no good way to do this other than looping through each value in the dictionary. This is because you've created a data structure to access the data quickly (O(1) time), but the drawback is that if you want to find the data through another index quickly, you'll have to search manually O(n) time for it.
If you really did care about the actual value of someId, then the canonical answer would be to create 2 separate dictionaries w/ the same data w/ different key values. This is very similar to having 2 indexes on a database table.

Including isNil in lodash chain

I have a collection of entities like this:
var entities = [
{
location: null,
label: 'xyz'
},
{
location: {
city: 'city'
},
label: 'xyz'
}
{
label: 'xyz'
}
];
Trying to filter out entities with location = null, undefined or not existing at all. Using lodash.
When testing the location of the first entity in this way, it's returning the correct answer true:
_.isNil(_(entities[0]).get('location'));
but when I trying to include the isNil in chain, it returns Cannot read property 'valueOf' of null error:
_(entities[0]).get('location').isNil
Can isNil included somehow in the lodash chain?
here is the issue: https://codepen.io/neptune01/pen/qjxJwr
I'll need to use it somehow in this way:
_(entities).omitBy(_.get('location').isNil)
or
_(entities).omitBy(_(entity).get('location').isNil)
isNil() is not chainable.
See a complete list of non-chainable methods here.
You can use it like this, for your particular problem:
_.omitBy(entities, (el) => _.isNil(el.location))
var entities = [{
location: null,
label: 'xyz'
},
{
location: {
city: 'city'
},
label: 'xyz'
}
];
console.log(_.omitBy(entities, (el) => _.isNil(el.location)));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

JS | lodash : recursive delete from deep nested array

Below is a recursive method to delete a comment from a deeply nested array. The code works, but here are my question:
QUESTION:
I'm using _.remove within the loop to find and remove a comment in the current array. It seems expensive for obvious reasons i.e. loop within a loop, but other approaches seems just as expensive. I'm sure there are better ways to do this.
WORKING EXAMPLE:
https://plnkr.co/edit/PeW5ZFLynO2q8VNqbAHx?p=preview
var comments = [
{
id: 1,
depth: 0,
subject: 'Subject one'
},
{
id: 2,
depth: 0,
subject: 'Subject two',
children: [
{
id: 3,
depth: 1,
subject: 'Subject two dot one'
},
{
id: 4,
depth: 1,
subject: 'Subject two dot two'
}
]
},
{
id: 5,
depth: 0,
subject: 'Subject three',
children: [
{
id: 6,
depth: 1,
subject: 'Subject three dot one'
},
{
id: 7,
depth: 1,
subject: 'Subject three dot two',
children: [
{
id: 8,
depth: 2,
subject: 'Subject three dot two dot one'
},
{
id: 9,
depth: 2,
subject: 'Subject three dot two dot two'
}
]
}
]
}
];
function deleteComment(comment, comments) {
var self = this,
db = [];
function removeComment(items, parent) {
_.forEach(items, function (item) {
// QUESTION - seems expensive as we have a loop in a loop
_.remove(items, function(item) {
if (item.id === comment.id) {
console.log(item);
return true;
}
// NOTE: use above for demo purposes
// return item.id === comment.id
});
_.has(item, 'children') ? removeComment(item.children, item) : 0;
});
}
removeComment(comments, db);
}
var commentToBeDeleted = {
id: 8,
depth: 2,
subject: 'Subject three dot two dot one'
};
deleteComment(commentToBeDeleted, comments);
You could probably find a way to do this more efficiently with a .reduce() function to combine .forEach and _.remove. However, if the code works, it works!
I am not sure if this is the most performant way to accomplish this, but this is the most succinct way I have found:
It turns out JSON.stringify provides a callback for each visited JSON value being converted, which you can use to determine if the value should be included in the string. You can use this to visit each value without having to do the traversing yourself.
From MDN
The replacer parameter can be either a function or an array. As a
function, it takes two parameters, the key and the value being
stringified. The object in which the key was found is provided as the
replacer's this parameter. Initially it gets called with an empty key
representing the object being stringified, and it then gets called for
each property on the object or array being stringified. It should
return the value that should be added to the JSON string,
In your case the function would look something like
function deleteComment(commentToBeDeleted, comments) {
return JSON.parse(JSON.stringify(comments, function(key, value) {
if (commentToBeDeleted.id !== value.id) {
return value;
}
}));
}
Note: you probably don't want to use this code as is, as it leaves an empty node, but, you can insert what ever you logic you like into the callback, and this should get you started.

ng-options model bind based on property

Hi I am quite new to angular programming and I had a question on angular's ng-options.
I have an object structure like
TestObj: { name: 'Name1', subNames: ['Subname1'] }
TestArr:
[{ name: 'Name1', subNames: ['Subname1'] },
{ name: 'Name2', subNames: ['Subname1'] },
{ name: 'Name3', subNames: ['Subname1'] }]
And I am trying to use ng-options to bind one of the TestArr objects to TestObj.
<select class="touchpoint-settings-create-channel-box ng-model="TestObj" ng-options="curTest.name for curTest in TestArr"></select>
However, is there any way to make TestObj bind to the object in TestArr that has the same 'name' property?
This jsfiddle is a good example of what I mean. http://jsfiddle.net/KN9xx/840/
When it first starts up, selectedPerson is set to an object similar to the first item in the array, but ng-options does not realize it is the same object.
Thank you
I would not recommend following the example in that jsfiddle. Essentially, you do not want TestObj AND TestArr. If TestObj is not just a reference to TestArr, they are not going to be the same object and you're duplicating data because Angular and JavaScript do not recognize that the two objects have the same keys and values when they are separate objects.
You should follow the example in this SO post: How to have a default option in Angular.js select box
Rather than using TestObj like you are, use ng-init to set the default value.
var TestArr =
[{ name: 'Name1', subNames: ['Subname1'] },
{ name: 'Name2', subNames: ['Subname1'] },
{ name: 'Name3', subNames: ['Subname1'] }];
<select
class="touchpoint-settings-create-channel-box
ng-init="TestObj = options[0]"
ng-model="TestObj"
ng-options="option.name for option in TestArr">
</select>
To illustrate my point on objects:
var obj1 = { name: 'Me' };
var obj2 = { name: 'Me' };
While obj1 and obj2 look exactly the same, the variables are just references to the underlying object, not the values, and the JS interpreter doesn't know that I intend both of those objects to be the same. However, if you strings or numbers, it works like you expect.
var me = 'Me';
var stillMe = 'Me';
console.log(obj1 === obj2); // prints false
console.log(me === stillMe); // prints true

How to loop over an array within a JavaScript object?

Very new to JavaScript objects, so I am not to sure how to go about doing this.
Within my object, I have an array called myArray. I am attempting to loop over it to print out everything on the page. Usually there is a a lot more data within the object, but it has been removed for this example.
This is my object:
var data = [
{
myArray:
{
name: 'name1',
code: 'code1',
data: {
date: '20-Apr-2014',
signal: 'signal1'
}
},
{
name: 'name2',
code: 'code2',
data: {
date: '21-Apr-2014',
signal: 'signal2'
}
}
}
]
This is my iteration code:
var arrayLength = data.myArray.length - 1;
for (var i = 0; i <= arrayLength; i++) {
var name = data.myArray[i].name;
console.log(name);
}
My code above should produce the results in the console name1 and name2. However, I am getting an error of Cannot read property 'length' of undefined.
How can I change my above code to do this?
Your object should use brackets for the array:
var data = {
myArray: [
{
name: 'name1',
code: 'code1',
data: {
date: '20-Apr-2014',
signal: 'signal1'
}
},
{
name: 'name2',
code: 'code2',
data: {
date: '21-Apr-2014',
signal: 'signal2'
}
}
]
}
I've also removed the outermost brackets, since it would appear from your question that your intent was to have a single array inside an object, and not an array of arrays.
With the object above, your iteration code will work fine.

Categories

Resources