This question already has answers here:
Why does JavaScript map function return undefined?
(13 answers)
Closed 1 year ago.
I don't want this map to return undefined how can i do that ?
var onCompareSelectedClick = function () {
var talentProfileInfoForAppliedResources = appliedResourcesEntries.map(function(res) {
console.log(res);
if(res.compareSelected == true) {
return data.getTalentProfileInfo(res.RES.RES_ID);
}
});
console.log(talentProfileInfoForAppliedResources);
this.openCompareTPDlg(talentProfileInfoForAppliedResources);
}.bind(this);
Just add else statement inside map method returning needed value, like:
if(res.compareSelected == true) {
return data.getTalentProfileInfo(res.RES.RES_ID);
} else {
return 'default_value';
}
TL;DR
Use the Array.filter method after Array.map to remove undefined elements in the new array.
Expanding on #Bloomca's answer:
As stated in the documentation provided here.
The map() method creates a new array with the results of calling a provided function on every element in this array.
Hence the reason why your new array contains undefined elements is because you are not explicitly calling return within the function on some elements that are called using the provided function. In Javascript, not explicitly calling return will nevertheless return undefined.
For example, in the following method newArray will be set to the logged result:
[ undefined, 2, 3 ]
newArray = [1,2,3].map(function(elem) { if (elem > 1) return elem })
console.log(newArray)
This is why the answer provided above will no longer result in undefined elements within the new array. The conditional will resolve if the condition res.compareSelected == true is not true to the return statement within the else block (note that you could simply remove the true here and simply put res.compareSelected which would be better practice).
Based on your question you may find using the Array.filter method to return an Array without the undefined values. And with only the values on which you have called the function data.getTalentProfileInfo(res.RES.RES_ID).
You could do this in the following manner:
var onCompareSelectedClick = function () {
var arr = appliedResourcesEntries.map(function(res) {
if(res.compareSelected == true) {
return data.getTalentProfileInfo(res.RES.RES_ID);
}
});
var talentProfileInfoForAppliedResources = arr.filter(function(elem) {
return elem;
});
console.log(talentProfileInfoForAppliedResources);
this.openCompareTPDlg(talentProfileInfoForAppliedResources);
}.bind(this);
You can read about the Array.filter method here.
Related
I am looping through an array of documents and setting two properties to the same value, however, doing a console.log shows the two properties have different values.
code:
this.logicItem.$promise.then(() => {
this.logicItem.getDocuments().$promise.then((docs: any) => {
docs.forEach(element => {
if (element.buildProgrammeActivityStatus === BUILD_PROGRAMME_ACTIVITY_STATUS.Confirmed ||
element.buildProgrammeActivityStatus === BUILD_PROGRAMME_ACTIVITY_STATUS.Complete) {
element.upper = true;
element.canUpload = true;
} else {
element.upper = false;
element.canUpload = false;
}
});
console.log(docs);
});
this.logicItem.reload(true);
});
When the code sets both properties to true, console logging the whole array shows that canUpload is always false no matter what, and upper is true if the code entered the true block. What could cause this bizarre behavior? I have tried it using array.map() and some other forms of looping, all with the same result.
The forEach statement should work fine. I tried to call it with some dummy data and I got the expected behavior in all cases. Have you tried to log each element in the forEach statement? If so the problem reproduce? Are the elements as expected?
Also what is the reload function does?
Array.foreach simply runs through an array and does not change the value of array. Array.map runs through the entire array and returns a new array but does not change the array itself you need to manually assign or rewrite the variable.
So here is my suggestion
this.logicItem.$promise.then(() => {
this.logicItem.getDocuments().$promise.then((docs: any) => {
//changed from forEach to map
docs = docs.map( element => {
if (element.buildProgrammeActivityStatus === BUILD_PROGRAMME_ACTIVITY_STATUS.Confirmed ||
element.buildProgrammeActivityStatus === BUILD_PROGRAMME_ACTIVITY_STATUS.Complete) {
element.upper = true;
element.canUpload = true;
} else {
element.upper = false;
element.canUpload = false;
}
//Added a return element
return element.
});
console.log(docs);
});
this.logicItem.reload(true);
});
I have this:
validateForm = () => {
for (let i = 0; i < formInputs.length; i++) {
const inputName = formInputs[i];
if (!this.state.form[inputName].length) {
return false;
}
}
}
which im refactoring in to this:
validateForm2 = () => {
Object.keys(this.state.form).map(input => {
if(!this.state.form[input].length) {
return false
}
return true;
})
}
the first one works, when i fill in my form and the function returns true, if one is empty it returns false.
however i cant seem to quite understand the return keyword to get the same result.
Object.keys says it returns an array but even if I say return Object.keys... or else {return true} I don't seem to get the same result. what am I misunderstanding about return?
You could use Array#every, which uses the return value for a short circuit and for returning the check of all truthy items.
validateForm2 = () =>
Object.keys(this.state.form).every(input => this.state.form[input].length);
Array#map utilizes the return value as new item for each item of the array for a new array, which is dicarded in the given example.
In the first example you have only one (arrow) function which returns either false or undefined.
In the second example you have outer (arrow) function that never returns anything - undefined to the calling code, and the second function that you pass as a parameter to Array.map method. return statements inside the parameter function are not returning anything from the outer function.
validateForm2 = () => {
var emptyItems = Object.keys(this.state.form).filter(input => {
return !this.state.form[input].length;
});
return emptyItems.length == 0;
}
You could modify your function to do what you want it to do.
validateForm2 = () => {
return Object.keys(this.state.form).every(input => {
return this.state.form[input].length;
})
}
You are checking that every property has a length (true). If one of them doesn't, your function returns false.
I think you can avoid using .map in favor of .every() which iterates over every single element and checks whether it has a length greater than zero.
const validateForm = (form) => Object.values(form).every((field) => field.length);
let semiEmptyForm = {
firstField : "",
secondfield : "notEmpty"
};
let nonEmptyForm = {
firstField : "notEmpty",
secondfield : "notEmpty"
};
console.log(validateForm(semiEmptyForm))
console.log(validateForm(nonEmptyForm))
This question already has answers here:
Test for existence of nested JavaScript object key
(64 answers)
Access Javascript nested objects safely
(14 answers)
Closed 5 years ago.
I am receiving a deeply nested object. I don't know which properties will be present. If I want to get the image, I can't just do this
data.opposite.info.logo.images.s.resized_urls.s,
Imagine this comes from a system where user can leave the logo empty, then my code will break. Do I need to check the existence of properties like this?
if(data.opposite){
if(data.opposite.info)
if(data.opposite.info.images)
//...etc
}
Use javascript's try { ... } catch(e) { ... } block.
try {
url = data.opposite.info.logo.images.s.resized_urls.s; }
catch(e) {
url = ''
}
Also loadash.js has a get method that can help you with this
var url = _.get(data, 'opposite.info.logo.images.s.resized_urls.s', '');
this will traverse deep into the object if the path exists and return the 's'. If it is not there, it returns the last argument which is '' in this case.
I'm trying to get value by scan object: jsfiddle
function getObjByProperty(obj, propertyName) {
if (obj instanceof Object) {
if (obj.hasOwnProperty(propertyName)) {
return obj[propertyName];
}
for (var val in obj) {
if (obj.hasOwnProperty(val)) {
var result = getObjByProperty(obj[val], propertyName);
if (result != null) {
return result;
}
}
}
} else {
return null;
}
}
var images = getObjByProperty(data, 'images');
if (images) {
console.log(images);
}
I've got a method that looks like this:
return AddedSoftware (software) {
this.softwares.map(function(soft) {
if(soft.id == software) {
return software.name;
}
})
}
So how could I break and return when soft.id == software now it loops through the entire softwares before it returns!
You would use find() instead
return function AddedSoftware (software) {
let res = this.softwares.find(soft => soft.id == software);
// return the software's name if there's a match, or undefined
return res ? res.name : res;
}
This will give you the first object matching your condition. You can then get software.name from that object.
Excerpt from the docs:
The find() method returns a value of the first element in the array that satisfies the provided testing function. Otherwise undefined is returned.
This question already has answers here:
How to avoid 'cannot read property of undefined' errors?
(18 answers)
Closed 2 years ago.
I am creating a personal script that in some instances gets the error:
Cannot read property '0' of undefined
I have something like this
item["OfferSummary"][0]["LowestUsedPrice"][0]["FormattedPrice"]
Is it possible to completely ignore/override this error so that it just prints n/a or -- in that scenario?
You can use try and catch to perform error handling.
You can use a boilerplate function to do so:
function get(obj, property) {
if (Array.isArray(property)) {
var current = obj;
for (var i = 0, l = property.length; i < l; ++i) {
if (Object(current) === current) current = current[property[i]];
else {
current = undefined;
break;
}
}
return current;
}
if (Object(obj) === obj) return obj[property];
}
Pass either a string or an array to get to find the property -- if not found, undefined will be returned.
Example:
get(window, ['location', 'href']); // "http://stackoverflow.com..."
get(Number, 'MAX_VALUE'); // 1.7976931348623157e+308
Even if you can use try and catch I wouldn't do that, I prefer avoid errors at all, so you'd just need to check the object you're reading:
if(item && item["OfferSummary"].length && item["OfferSummary"][0]["LowestUsedPrice"].length) {
//then do whatever
}
if you know that item is always defined you can avoid to check it in the if.
Similar to Qantas' answer, but using an in test. Always expects the property list to be an array, I can't see the point of using this to get a single property so no concession for that case:
function get2(obj, prop) {
for (var i=0, iLen=prop.length - 1; i<iLen; i++) {
if (typeof obj[prop[i]] == 'object') {
obj = obj[prop[i]];
} else {
// Property not found, return undefined (or other suitable value)
return;
}
}
return obj[prop[i]];
}
var foo = {foo:{bar:{meh:'meh!'}}};
var fum = {meh:'meh!'};
console.log(get2(foo,['foo','bar','meh'])); // meh!
console.log(get2(fum,['meh'])); // meh!
console.log(get2(Number,['MAX_VALUE'])); // 1.7976931348623157e+308
console.log(get2(Object,['prototype','toString'])); // function toString() { ... }
Edit
Per Qantas' comment, the test has been updated.