Here's the thing.. I want to overwite an object with if-else condition inside angular.forEach with this controller, basically "k1" has an original keyword and I want to replace it with a new keyword. what do you think is the best way to display the new input object?
$scope.SubmitKeyword = function (key, new_keyword) {
console.log(key, new_keyword)
$scope.new_keyword = new_keyword;
if ($scope.new_keyword == null || $scope.new_keyword == undefined || $scope.new_keyword == "") {
alert('Invalid input!')
return
}
angular.forEach($scope.new_campaign_keywords, function (v, k) {
console.log(v,k)
if (k == key) {
if (v['orig_keyword'] == new_keyword) {
alert('No Changes Found!')
return
} else {
console.log('changes detected')
var a = 0;
angular.forEach($scope.campaigns, function (v1,k1) {
a++
console.log(k1)
if (k1 == a) {
//display the new keyword
else {
//remain the original keyword
}
}
})
}
}
})
};
enter image description here
enter image description here
Use the hasOwnProperty method to detect the existence of a property:
$scope.SubmitKeyword = function (key, new_keyword) {
var obj = $scope.new_campaign_keywords;
console.log(key, new_keyword)
$scope.new_keyword = new_keyword;
if (!new_keyword) {
alert('Invalid input!');
return;
};
if (obj.hasOwnProperty(new_keyword)) {
alert('New keyword in use');
return;
};
//ELSE
console.log('changes detected');
obj[new_keyword] = obj[key];
delete obj[key];
};
Use the delete operator to remove the old keyword.
You have different options to do this, if you are using ES6 or Typescript you can use the spread operator to copy only certain properties from an Object
let obj= { bar: true, foo1: true, foo2:true};
if(someValidation){
let { bar, ...rest} = obj;
obj = {
...rest,
newKey: bar, //or whatever value/key you want
}
}
Now since I see ES5 code only on your code example, I would argue that you are complicating things a little bit, first of all is not a good idea to use a forEach to modify the same array you are iterating over.
Use a map function and do the changes there. You can use the delete operator to eliminate the property you don't want, but is well know that has some performance issues, so let's go with this approach:
$scope.campaigns = $scope.campaigns.map(function (v) {
a++
if (condition) {
return {
newBar: v.bar,
foo1: v.foo1,
foo2: v.foo2,
};
}
return v;
});
The other benefit is that now you are making a new array and replacing the current $scope variable value once, rather than modifying every single element, since the map return value will be done once the new list is created.
If you need to iterate over the keys dynamically you can use Object.keys to iterate over them and do the same approach, create a new object, and return it to the map, or return the same initial object.
Related
How can I add getters (or prototype/method) to all object.
I have an object that look like:
foo.bar.text
//or
foo.bar.child.text
text - is an array of strings, but I need only one of them.
Each time when I get this value, I want get only one fixed index (this index saved in other variable).
So what I need in result:
foo.text = ['a','b']
foo.bar.text = ['c','d']
foo.bar.someChild.text = [null, undefined]
x = 1;
// here we make some magic
console.log(foo.text) // b
console.log(foo.bar.text) // d
console.log(foo.bar.someChild.text) // undefined
So if any object contains an array text, if we try get it, we get not array but some defined item from it.
Manually point on item I can't so foo.bar.text[x] is not an option.
Name of array and variable that we get is optional, for example we can save array in fullText and try get text. As if text = fullText[x].
Can somebody advice how I can implement this, getter, setter, prototype?
Update
Proxy seems is my option, thanks for advice!
I would suggest you apply Proxy recursively to the foo object.
// the code is handwriting without test
var handler = {
get: (target, prop) => {
if (prop === 'text') {
if (target[prop] instanceof Array) {
return target[prop][x];
} else {
// dealing with non-array value
}
} else if (typeof target[prop] === 'object') {
return new Proxy(target[prop], handler);
} else {
return target[prop];
}
}
}
var newFoo = new Proxy(foo, handler);
I'm building an utility function that should search for a property name and return its value once it is found. It should do this recursively:
// Function
util.findVal = (object, propName) => {
for (let key in object) {
if (key === propName) {
console.log(propName)
console.log(object[key])
return object[key]
} else {
util.findVal(object[key], propName)
}
}
}
// Input
object: {
photo: {
progress: 20
}
}
// Usage
util.findVal(object, 'progress')
However the console log goes forever and the browser crashes. What am I doing wrong?
EDIT:
This is how I'm calling the function:
// Input
item: {
photo: {
file: {},
progress: 20
}
}
this.findProgress(item)
methods: {
findProgress (item) {
return util.findVal(item, this.propName)
}
}
You could use Object.keys and iterate with Array#some.
function findVal(object, key) {
var value;
Object.keys(object).some(function(k) {
if (k === key) {
value = object[k];
return true;
}
if (object[k] && typeof object[k] === 'object') {
value = findVal(object[k], key);
return value !== undefined;
}
});
return value;
}
var object = { photo: { progress: 20 }};
console.log(findVal(object, 'progress'));
Your code has a few errors:
You're recursively calling util.findVal but not returning the result of the call. Code should be return util.findVal(...)
You're not passing the attribute name key to the recursive call
You're not handling the possibility of a reference loop
If an object contains a key and also a sub-object that contains the key which value is returned is random (depends on the sequence in which the keys are analyzed)
The third problem is what can cause infinite recursion, for example:
var obj1 = {}, obj2 = {};
obj1.x = obj2; obj2.y = obj1;
if you just keep looking recursively searching in obj1 or obj2 could lead to infinite recursion.
Unfortunately for reasons not clear to me in Javascript is impossible to know the object "identity"... (what Python id(x) does) you can only compare an object to another. This means that to know if an object has already been seen in the past you need a linear scan with known objects.
ES6 added the possibility to check object identity with Set and Map where objects can be used as keys. This allows for faster (sub-linear) search times.
A search solution that runs in depth order could be for example:
function findVal(obj, key) {
var seen = new Set, active = [obj];
while (active.length) {
var new_active = [], found = [];
for (var i=0; i<active.length; i++) {
Object.keys(active[i]).forEach(function(k){
var x = active[i][k];
if (k === key) {
found.push(x);
} else if (x && typeof x === "object" &&
!seen.has(x)) {
seen.add(x);
new_active.push(x);
}
});
}
if (found.length) return found;
active = new_active;
}
return null;
}
given an object and an attribute name, returns all the values found with that name at the first depth they are found (there can be more than one value: for example when searching {x:{z:1}, y:{z:2}} for the key "z" two values are at the same depth).
The function also correctly handles self-referencing structures avoiding infinite search.
Don't write your own utility if you can avoid it.
Use something like jsonpath
Some examples of supported syntax:
JSONPath Description
$.store.book[*].author The authors of all books in the store
$..author All authors
$.store.* All things in store, which are some books and a red bicycle
$.store..price The price of everything in the store
$..book[2] The third book
$..book[(#.length-1)] The last book via script subscript
$..book[-1:] The last book via slice
$..book[0,1] The first two books via subscript union
$..book[:2] The first two books via subscript array slice
$..book[?(#.isbn)] Filter all books with isbn number
try changing else statement like this
return util.findVal(object[key],propName)
I know this is an old post, but I found it helpful to answer a problem I had with recursively finding a value by it's key. I further developed the answer given by Nina Scholz, and came up with the following. It should be quicker as it is not creating an array of all of the keys each time it is recursively invoked. Also, this will explicitly return false if the key is not found.
function findVal(obj, keyToFind) {
if (obj[keyToFind]) return obj[keyToFind];
for (let key in obj) {
if (typeof obj[key] === 'object') {
const value = findVal(obj[key], keyToFind);
if (value) return value;
}
}
return false;
}
var object = { photo: { progress: 20 }};
console.log(findVal(object, 'progress'));
I think you are saying that you want to look for the property name anywhere recursively within the objects tree of properties and sub-properties. If so, here is how I would approach this:
var object1 = _getInstance(); // somehow we get an object
var pname = 'PropNameA';
var findPropertyAnywhere = function (obj, name) {
var value = obj[name];
if (typeof value != 'undefined') {
return value;
}
foreach(var key in obj) {
var v2 = findPropertyAnywhere(obj[key], name);
if (typeof v2 != 'undefined') {
return v2;
}
}
return null;
}
findPropertyAnywhere(object1, pname);
Think about it if there is no key found.
I think you could do something like this instead of search
return object[propName] || null
In your code there was a breakpoint missing, I guess you are trying to search inside the whole object not just the directly related attributes so here is an edit for you code
EDIT:
util.findVal = (object, propName) =>{
if(!!object[propName]){
return object[propName]
}else{
for (let key in object) {
if(typeof object[key]=="object"){
return util.findVal(object[key], propName)
}else{
return null
}
}
}
}
Found this question in the realm of needing a general solution to check if an object contains a specific value anywhere in its hierarchy (regardless of the key), which can include arrays of course. So the following does not answer OPs question directly or improve upon other solutions but it might help others looking for the same thing I did and finding this post:
function hasValue(object, value) {
return Object.values(object).some(function(val) {
if (val === value) {
return true;
}
if (val && typeof val === 'object') {
return hasValue(val, value);
}
if (val && val.isArray()) {
return val.some((obj) => {
return hasValue(obj, value);
})
}
});
}
it is of course inspired by #Nina Scholz 's solution!
An answer depends a on how complex you want to get. For example a JSON parsed array doesn't contain functions - and I'm fairly certain it won't contain property value set to a parent node in object tree.
This version returns the property value of the first property name found whilst searching the object tree. undefined is returned if either the named property was not found or has a value of undefined. Some modifications would be needed to tell the difference. It does not re-search parent nodes already being searched, nor try to scan null objects!
let util = {};
util.findVal = (object, propName, searched=[]) => {
searched.push( object)
for (let key in object) {
if (key === propName) {
return object[key]
}
else {
let obj = object[ key]
if( obj && (typeof obj == "object" || typeof obj == "function")) {
if( searched.indexOf(obj) >=0) {
continue
}
let found = util.findVal(obj, propName, searched)
if( found != searched) {
return found
}
}
}
}
searched.pop();
// not in object:
return searched.length ? searched : undefined
}
I ended up writing this function.
It is a refactor of a function found here: Recursively looping through an object to build a property list
added a depth parameter to avoid stack overflow in chrome devtools.
function iterate(obj, context, search, depth) {
for (var property in obj) {
if (Object.prototype.hasOwnProperty.call(obj, property)) {
if(typeof obj[property] == 'function') continue;
if( property == search ){
console.log(context+property);
return;
}
if (typeof obj[property] == "object" && depth < 7) {
//console.log('--- going in: ' + context+property);
iterate(obj[property], context+property+'.', search, depth+1);
}
/*else {
console.log(context+property);
}*/
}
}
}
Returns the value of the field with the specified name.
data is the root node/object.
keyName is a string name of the field/member.
If keyName specifies a field that is itself an object, then that object is returned.
function find (data, keyName) {
for (const key in data) {
const entry = data[key]
if (key === keyName)
return entry
if (typeof entry === 'object') {
const found = find(entry, keyName)
if (found)
return found
}
}
}
The for loop goes through each field and if that field is an object then it will recurse into that object.
Here is a piece of code which find the key you are looking for in your rootObj tree. And add it to the root object. So by the end you will have access to you key like this rootObj[key].
findKeyVal(object, key, rootObj) {
if(object instanceof Object) {
let keys = Object.keys(object);
if(keys.includes(key) && !isNullOrUndefined(object[key])) {
rootObj[key] = object[key];
return;
}
else {
keys.filter(k => object[k] instanceof Object).forEach( k => {
this.findKeyVal(object[k], key, rootObj);
})
}
}
}
Old question, but to check if the property exists anywhere in the hierarchy of an object, try this simple option
var obj = {
firstOperand: {
firstOperand: {
firstOperand: {
sweptArea: 5
}
}
}
};
function doesPropertyExists ( inputObj, prop )
{
return JSON.stringify(obj).indexOf( "\""+ prop +"\":" ) != -1;
};
console.log( doesPropertyExists( obj, "sweptArea" ) );
console.log( doesPropertyExists( obj, "firstOperand" ) );
console.log( doesPropertyExists( obj, "firstOperand22" ) );
I'm building an utility function that should search for a property name and return its value once it is found. It should do this recursively:
// Function
util.findVal = (object, propName) => {
for (let key in object) {
if (key === propName) {
console.log(propName)
console.log(object[key])
return object[key]
} else {
util.findVal(object[key], propName)
}
}
}
// Input
object: {
photo: {
progress: 20
}
}
// Usage
util.findVal(object, 'progress')
However the console log goes forever and the browser crashes. What am I doing wrong?
EDIT:
This is how I'm calling the function:
// Input
item: {
photo: {
file: {},
progress: 20
}
}
this.findProgress(item)
methods: {
findProgress (item) {
return util.findVal(item, this.propName)
}
}
You could use Object.keys and iterate with Array#some.
function findVal(object, key) {
var value;
Object.keys(object).some(function(k) {
if (k === key) {
value = object[k];
return true;
}
if (object[k] && typeof object[k] === 'object') {
value = findVal(object[k], key);
return value !== undefined;
}
});
return value;
}
var object = { photo: { progress: 20 }};
console.log(findVal(object, 'progress'));
Your code has a few errors:
You're recursively calling util.findVal but not returning the result of the call. Code should be return util.findVal(...)
You're not passing the attribute name key to the recursive call
You're not handling the possibility of a reference loop
If an object contains a key and also a sub-object that contains the key which value is returned is random (depends on the sequence in which the keys are analyzed)
The third problem is what can cause infinite recursion, for example:
var obj1 = {}, obj2 = {};
obj1.x = obj2; obj2.y = obj1;
if you just keep looking recursively searching in obj1 or obj2 could lead to infinite recursion.
Unfortunately for reasons not clear to me in Javascript is impossible to know the object "identity"... (what Python id(x) does) you can only compare an object to another. This means that to know if an object has already been seen in the past you need a linear scan with known objects.
ES6 added the possibility to check object identity with Set and Map where objects can be used as keys. This allows for faster (sub-linear) search times.
A search solution that runs in depth order could be for example:
function findVal(obj, key) {
var seen = new Set, active = [obj];
while (active.length) {
var new_active = [], found = [];
for (var i=0; i<active.length; i++) {
Object.keys(active[i]).forEach(function(k){
var x = active[i][k];
if (k === key) {
found.push(x);
} else if (x && typeof x === "object" &&
!seen.has(x)) {
seen.add(x);
new_active.push(x);
}
});
}
if (found.length) return found;
active = new_active;
}
return null;
}
given an object and an attribute name, returns all the values found with that name at the first depth they are found (there can be more than one value: for example when searching {x:{z:1}, y:{z:2}} for the key "z" two values are at the same depth).
The function also correctly handles self-referencing structures avoiding infinite search.
Don't write your own utility if you can avoid it.
Use something like jsonpath
Some examples of supported syntax:
JSONPath Description
$.store.book[*].author The authors of all books in the store
$..author All authors
$.store.* All things in store, which are some books and a red bicycle
$.store..price The price of everything in the store
$..book[2] The third book
$..book[(#.length-1)] The last book via script subscript
$..book[-1:] The last book via slice
$..book[0,1] The first two books via subscript union
$..book[:2] The first two books via subscript array slice
$..book[?(#.isbn)] Filter all books with isbn number
try changing else statement like this
return util.findVal(object[key],propName)
I know this is an old post, but I found it helpful to answer a problem I had with recursively finding a value by it's key. I further developed the answer given by Nina Scholz, and came up with the following. It should be quicker as it is not creating an array of all of the keys each time it is recursively invoked. Also, this will explicitly return false if the key is not found.
function findVal(obj, keyToFind) {
if (obj[keyToFind]) return obj[keyToFind];
for (let key in obj) {
if (typeof obj[key] === 'object') {
const value = findVal(obj[key], keyToFind);
if (value) return value;
}
}
return false;
}
var object = { photo: { progress: 20 }};
console.log(findVal(object, 'progress'));
I think you are saying that you want to look for the property name anywhere recursively within the objects tree of properties and sub-properties. If so, here is how I would approach this:
var object1 = _getInstance(); // somehow we get an object
var pname = 'PropNameA';
var findPropertyAnywhere = function (obj, name) {
var value = obj[name];
if (typeof value != 'undefined') {
return value;
}
foreach(var key in obj) {
var v2 = findPropertyAnywhere(obj[key], name);
if (typeof v2 != 'undefined') {
return v2;
}
}
return null;
}
findPropertyAnywhere(object1, pname);
Think about it if there is no key found.
I think you could do something like this instead of search
return object[propName] || null
In your code there was a breakpoint missing, I guess you are trying to search inside the whole object not just the directly related attributes so here is an edit for you code
EDIT:
util.findVal = (object, propName) =>{
if(!!object[propName]){
return object[propName]
}else{
for (let key in object) {
if(typeof object[key]=="object"){
return util.findVal(object[key], propName)
}else{
return null
}
}
}
}
Found this question in the realm of needing a general solution to check if an object contains a specific value anywhere in its hierarchy (regardless of the key), which can include arrays of course. So the following does not answer OPs question directly or improve upon other solutions but it might help others looking for the same thing I did and finding this post:
function hasValue(object, value) {
return Object.values(object).some(function(val) {
if (val === value) {
return true;
}
if (val && typeof val === 'object') {
return hasValue(val, value);
}
if (val && val.isArray()) {
return val.some((obj) => {
return hasValue(obj, value);
})
}
});
}
it is of course inspired by #Nina Scholz 's solution!
An answer depends a on how complex you want to get. For example a JSON parsed array doesn't contain functions - and I'm fairly certain it won't contain property value set to a parent node in object tree.
This version returns the property value of the first property name found whilst searching the object tree. undefined is returned if either the named property was not found or has a value of undefined. Some modifications would be needed to tell the difference. It does not re-search parent nodes already being searched, nor try to scan null objects!
let util = {};
util.findVal = (object, propName, searched=[]) => {
searched.push( object)
for (let key in object) {
if (key === propName) {
return object[key]
}
else {
let obj = object[ key]
if( obj && (typeof obj == "object" || typeof obj == "function")) {
if( searched.indexOf(obj) >=0) {
continue
}
let found = util.findVal(obj, propName, searched)
if( found != searched) {
return found
}
}
}
}
searched.pop();
// not in object:
return searched.length ? searched : undefined
}
I ended up writing this function.
It is a refactor of a function found here: Recursively looping through an object to build a property list
added a depth parameter to avoid stack overflow in chrome devtools.
function iterate(obj, context, search, depth) {
for (var property in obj) {
if (Object.prototype.hasOwnProperty.call(obj, property)) {
if(typeof obj[property] == 'function') continue;
if( property == search ){
console.log(context+property);
return;
}
if (typeof obj[property] == "object" && depth < 7) {
//console.log('--- going in: ' + context+property);
iterate(obj[property], context+property+'.', search, depth+1);
}
/*else {
console.log(context+property);
}*/
}
}
}
Returns the value of the field with the specified name.
data is the root node/object.
keyName is a string name of the field/member.
If keyName specifies a field that is itself an object, then that object is returned.
function find (data, keyName) {
for (const key in data) {
const entry = data[key]
if (key === keyName)
return entry
if (typeof entry === 'object') {
const found = find(entry, keyName)
if (found)
return found
}
}
}
The for loop goes through each field and if that field is an object then it will recurse into that object.
Here is a piece of code which find the key you are looking for in your rootObj tree. And add it to the root object. So by the end you will have access to you key like this rootObj[key].
findKeyVal(object, key, rootObj) {
if(object instanceof Object) {
let keys = Object.keys(object);
if(keys.includes(key) && !isNullOrUndefined(object[key])) {
rootObj[key] = object[key];
return;
}
else {
keys.filter(k => object[k] instanceof Object).forEach( k => {
this.findKeyVal(object[k], key, rootObj);
})
}
}
}
Old question, but to check if the property exists anywhere in the hierarchy of an object, try this simple option
var obj = {
firstOperand: {
firstOperand: {
firstOperand: {
sweptArea: 5
}
}
}
};
function doesPropertyExists ( inputObj, prop )
{
return JSON.stringify(obj).indexOf( "\""+ prop +"\":" ) != -1;
};
console.log( doesPropertyExists( obj, "sweptArea" ) );
console.log( doesPropertyExists( obj, "firstOperand" ) );
console.log( doesPropertyExists( obj, "firstOperand22" ) );
Let's say we have this JavaScript object:
var object = {
innerObject:{
deepObject:{
value:'Here am I'
}
}
};
How can we check if value property exists?
I can see only two ways:
First one:
if(object && object.innerObject && object.innerObject.deepObject && object.innerObject.deepObject.value) {
console.log('We found it!');
}
Second one:
if(object.hasOwnProperty('innerObject') && object.innerObject.hasOwnProperty('deepObject') && object.innerObject.deepObject.hasOwnProperty('value')) {
console.log('We found it too!');
}
But is there a way to do a deep check? Let's say, something like:
object['innerObject.deepObject.value']
or
object.hasOwnProperty('innerObject.deepObject.value')
There isn't a built-in way for this kind of check, but you can implement it easily. Create a function, pass a string representing the property path, split the path by ., and iterate over this path:
Object.prototype.hasOwnNestedProperty = function(propertyPath) {
if (!propertyPath)
return false;
var properties = propertyPath.split('.');
var obj = this;
for (var i = 0; i < properties.length; i++) {
var prop = properties[i];
if (!obj || !obj.hasOwnProperty(prop)) {
return false;
} else {
obj = obj[prop];
}
}
return true;
};
// Usage:
var obj = {
innerObject: {
deepObject: {
value: 'Here am I'
}
}
}
console.log(obj.hasOwnNestedProperty('innerObject.deepObject.value'));
You could make a recursive method to do this.
The method would iterate (recursively) on all 'object' properties of the object you pass in and return true as soon as it finds one that contains the property you pass in. If no object contains such property, it returns false.
var obj = {
innerObject: {
deepObject: {
value: 'Here am I'
}
}
};
function hasOwnDeepProperty(obj, prop) {
if (typeof obj === 'object' && obj !== null) { // only performs property checks on objects (taking care of the corner case for null as well)
if (obj.hasOwnProperty(prop)) { // if this object already contains the property, we are done
return true;
}
for (var p in obj) { // otherwise iterate on all the properties of this object.
if (obj.hasOwnProperty(p) && // and as soon as you find the property you are looking for, return true
hasOwnDeepProperty(obj[p], prop)) {
return true;
}
}
}
return false;
}
console.log(hasOwnDeepProperty(obj, 'value')); // true
console.log(hasOwnDeepProperty(obj, 'another')); // false
Alternative recursive function:
Loops over all object keys. For any key it checks if it is an object, and if so, calls itself recursively.
Otherwise, it returns an array with true, false, false for any key with the name propName.
The .reduce then rolls up the array through an or statement.
function deepCheck(obj,propName) {
if obj.hasOwnProperty(propName) { // Performance improvement (thanks to #nem's solution)
return true;
}
return Object.keys(obj) // Turns keys of object into array of strings
.map(prop => { // Loop over the array
if (typeof obj[prop] == 'object') { // If property is object,
return deepCheck(obj[prop],propName); // call recursively
} else {
return (prop == propName); // Return true or false
}
}) // The result is an array like [false, false, true, false]
.reduce(function(previousValue, currentValue, index, array) {
return previousValue || currentValue;
} // Do an 'or', or comparison of everything in the array.
// It returns true if at least one value is true.
)
}
deepCheck(object,'value'); // === true
PS: nem035's answer showed how it could be more performant: his solution breaks off at the first found 'value.'
My approach would be using try/catch blocks. Because I don't like to pass deep property paths in strings. I'm a lazy guy who likes autocompletion :)
JavaScript objects are evaluated on runtime. So if you return your object statement in a callback function, that statement is not going to be evaluated until callback function is invoked.
So this function just wraps the callback function inside a try catch statement. If it catches the exception returns false.
var obj = {
innerObject: {
deepObject: {
value: 'Here am I'
}
}
};
const validate = (cb) => {
try {
return cb();
} catch (e) {
return false;
}
}
if (validate(() => obj.innerObject.deepObject.value)) {
// Is going to work
}
if (validate(() => obj.x.y.z)) {
// Is not going to work
}
When it comes to performance, it's hard to say which approach is better.
On my tests if the object properties exist and the statement is successful I noticed using try/catch can be 2x 3x times faster than splitting string to keys and checking if keys exist in the object.
But if the property doesn't exist at some point, prototype approach returns the result almost 7x times faster.
See the test yourself: https://jsfiddle.net/yatki/382qoy13/2/
You can also check the library I wrote here: https://github.com/yatki/try-to-validate
I use try-catch:
var object = {
innerObject:{
deepObject:{
value:'Here am I'
}
}
};
var object2 = {
a: 10
}
let exist = false, exist2 = false;
try {
exist = !!object.innerObject.deepObject.value
exist2 = !!object2.innerObject.deepObject.value
}
catch(e) {
}
console.log(exist);
console.log(exist2);
Try this nice and easy solution:
public hasOwnDeepProperty(obj, path)
{
for (var i = 0, path = path.split('.'), len = path.length; i < len; i++)
{
obj = obj[path[i]];
if (!obj) return false;
};
return true;
}
In case you are writing JavaScript for Node.js, then there is an assert module with a 'deepEqual' method:
const assert = require('assert');
assert.deepEqual(testedObject, {
innerObject:{
deepObject:{
value:'Here am I'
}
}
});
I have created a very simple function for this using the recursive and happy flow coding strategy. It is also nice to add it to the Object.prototype (with enumerate:false!!) in order to have it available for all objects.
function objectHasOwnNestedProperty(obj, keys)
{
if (!obj || typeof obj !== 'object')
{
return false;
}
if(typeof keys === 'string')
{
keys = keys.split('.');
}
if(!Array.isArray(keys))
{
return false;
}
if(keys.length == 0)
{
return Object.keys(obj).length > 0;
}
var first_key = keys.shift();
if(!obj.hasOwnProperty(first_key))
{
return false;
}
if(keys.length == 0)
{
return true;
}
return objectHasOwnNestedProperty(obj[first_key],keys);
}
Object.defineProperty(Object.prototype, 'hasOwnNestedProperty',
{
value: function () { return objectHasOwnNestedProperty(this, ...arguments); },
enumerable: false
});
For example, this is the value of the object I am processing:
object = {"message":"success","dataList":{"state":"error","count":"25"}}
I know that to check if key "message" exists, I can do the following:
if(object['message']){
//"message" exists. do stuff.
} else{
//"message" does not exist
}
How do I check for the existence of "state" or "count" though?
if(object['dataList']['state']){
// dataList["state"] exists. do stuff.
} else {
// dataList["state"] does not exist
}
or the (in my opinion) more readable:
if(object.dataList.state){ ... }
Edit: It would also be a good idea to check for all parent objects so you will not get an unexpected error when, for example, dataList does not exist on the object:
if (object && object.dataList && object.dataList.state)
try like this:
object = {"message":"success","dataList":{"state":"error","count":"25"}};
if(object.message =='success'){
console.log(object.dataList);// your datalist object here use it
console.log(object.dataList.state);
console.log(object.dataList.count);
} else{
//"message" does not exist
}
if you are trying to check state do this:
if(typeof(object.dataList.state) !='undefined' && object.dataList.state.length > 0){
// dataList.state exists. do stuff.
} else {
// dataList.state does not exist
}
if (object.dataList.state || object.dataList.count) {
// ...
}
First of all, if you are checking the existence of a property, you should use if ('message' in object). If you use if (object['message']), for the case object = {'message': null}, the result is wrong.
In your question, the object is nested into two layers. If there are more than two, you can try a generic solution using recursion:
function findProperty (obj, key) {
if (typeof obj === "object") {
if (key in obj) return true;
var childReturned = false;
for (k in obj) {
childReturned = findProperty(obj[k], key);
if (childReturned) return true;
}
}
return false;
}
var obj = {"message":"success","dataList":{"state":"error","count":"25"}};
findProperty(obj, 'message'); // => true
findProperty(obj, 'dataList'); // => true
findProperty(obj, 'state'); // => true
findProperty(obj, 'count'); // => true