React: .map method statement returns undefined - javascript

I have the following function;
const ListallSpaces = newSubject.map(mySpaces => {
const urlToBeSplit = mySpaces.s
const onlySpaceNames = urlToBeSplit.split('/')[5]
const subject = []
return (
subject.push({subject: [onlySpaceNames]}),
console.log("subject", subject)
)
})
console.log(ListallSpaces)
if i console.log(subject) it returns an array containing a certain space, which is the value i need. However, if i console.log the ListallSpaces it returns undefined. is there a reason why?

Return something.
The below example will return an array with one element. That element will be an object.
const ListallSpaces = newSubject.map(mySpaces => {
const urlToBeSplit = mySpaces.s
const onlySpaceNames = urlToBeSplit.split('/')[5]
const subject = [{subject: [onlySpaceNames]}]
return subject
})

it is giving undefined as in your return statement your push command gives 1 and console.log gives you undefined.
To make this work you have to return the subject.
just try this.
subject.push({ subject: [onlySpaceNames] }); return subject;

Because console.log returns undefined.

Related

How to access object provided by onloadedmetadata?

Im trying to acceess a value in a object resulting from onloadedmetadata. When I console log the entire object audioDuration i can see and access the contained value. When i console log the exact element AudioDuration.length it returns undefined.
var audioDuration = {};
convertedAudio.onloadedmetadata = () => {
audioDuration.length = convertedAudio.duration
};
console.log (audioDuration) // displays object {length: 25.547755}
console.log (audioDuration.length) // displays undefined
I want to use the value of AudioDuration.length directly and not the entire object.
your problem is due to the value of audioDuration is set only in callback and the console.log is used directly after onloadedmetadata so the console.log will run before the value is set. Two ways to fix that, one way is to do console.log inside onloadmetadata. The other way is to return a promise and await for the result.
const audioDuration = {}
const getDuration = () => new Promise(resolve => {
convertedAudio.onloadedmetadata = () => {
resolve(convertedAudio.duration);
}
})
getDuration().then(l => { console.log(l); audioDuration.length = l; })
Try this
var audioDuration = {};
convertedAudio.onloadedmetadata = () => {
if(convertedAudio.duration!=undefined){audioDuration.length = convertedAudio.duration}
};
console.log (audioDuration) // displays object {length: 25.547755}
console.log (audioDuration.length) // displays idk, u see what it does since i can't replicated convertedAudio

How to deal with a `Variable 'xxx' is used before being assigned.`

I have a code block like below where I need to find something inside a loop, and also return a second variable. So I can't use a simple Array.find or Array.some good ole' for...of is my friend. map/filter don't allow a break and find can only return actual elements from the array, not a related calculation.
But the below within typescript is giving me an unavoidable error.
I'm wondering if either there's a more idiomatic way to do this, or a better structure / place to declare the variable?
Variable 'found' is used before being assigned.
let found: ParseResult
// breaks when first item found but we capture a different value
for (const rule of ParserRules) {
// const rex = new RegExp(route.match)
const parsed = rule.rex.exec(input)
if (parsed) {
found = { parsed, rule }
break
}
}
// #ts-ignore
return found // FIXME used before defined?
Here are the various JS iterator methods I tried...
const ar = [1, 2, 3, 4]
const log = console.log
const finder = (list) => {
console.log('map', list.map(it => it === 3))
console.log('find', list.find(it => it === 3))
console.log('some', list.some(it => it === 3))
console.log('filter', list.filter(it => it === 3))
console.log('find', list.find(it => {
if (it === 3) return it * 2 // value coerced to T|F
}))
console.log('filter', list.filter(it => {
if (it === 3) return it * 2 // value coerced to T|F
}))
const arr = list.forEach((k) => {
if (k === 3) return ('here')
})
log('arr', arr)
let found
for (const elem of list) {
log('elem of', elem)
if (elem === 2) {
found = elem
break
}
}
log('found', found)
}
finder(ar)
The summary of your problem is that a function returning a value in a variable when, at times, the logic doesn't get a chance to assign any value to it.
You can either initialize the variable with a default value or, at the point of returning, check if it really has a value.
let found: ParseResult= {}
OR
return found || false //Or an empty object etc
This can be done in many ways but what might suit your case would be
ar
.map((rule) => {
const parsed = rule.rex.exec(input)
if (parsed) {
return { parsed, rule }
}
})
.find((x) => !!x)
Yes you are looping it once more but this is more readable. Also it would not be that costly.
If your processing is heavy, you can try this approach as well but this will be a custom implementation and will not come out of the box:
function getParsedValue(ar, input) {
let parsed;
const rule = ar
.find((rule) => {
parsed = rule.rex.exec(input);
return !!parsed;
})
return !!rule ? { rule, parsed } : null
}

Get rid of `undefined` in a array of objects

I have this function that receives params as an argument:
export const addCalculations = (params) => {
console.log(params);
};
Then I want to access to the id value but when I do params[0].id it throws an error (Cannot read property id of undefined). When I see the console, that function is being called multiple times and it returns undefined sometimes. How can I get rid of those undefined and only get the last array?
params[0] itself is undefined so before going to call params[0].id you should make a check
if (params[0]) {
id = params[0].id;
...
}
If you want to filter the array of params, you can use filter function
filterd = params.filter( x => {
if (x) {
return true;
}
return false;
})
//continue with filtered
...

understanding the return keyword

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))

Returning from .filter nested within .ForEach

I have this code that i have been figuring out by trial and error:
let _fk = this.selectedIaReportDiscussedTopic$
.map((discussionTopic) => {return discussionTopic.fk_surveyanswer}) //["string"]
.forEach((fk) => {
let surveyAnswerMatches = this.surveyAnswers.filter((sa) => {
return fk === sa._id
})
console.log('surveyAnswerMatches', surveyAnswerMatches)//[object] <- this contains what I want and so I return it below, but nothing shows in console.log(_fk)
return surveyAnswerMatches
})
console.log('this is fk', _fk) //'undefined'
What I want, is to be able to access the surveyAnswerMatches array from outside of the function. I thought returning the array would allow me to access it through the _fk variable.
How come the return value does not get assigned to _fk?
What would allow me to access the surveyAnswerMatches from out outside all the .forEach and .map calls?
Thanks SO community!
Edit: More Info
console.log('this.selectedIaReportDiscussedTopic$', this.selectedIaReportDiscussedTopic$) //[{_id: "discussed_topic_2016-11-03T11:48:48Z_1", fk_surveyanswer:"surveyanswer_2016-11-03T11:48:48Z_1" }]
let surveyAnswerMatches = this.selectedIaReportDiscussedTopic$
.map((discussionTopic) => {return discussionTopic.fk_surveyanswer})
.map((fk) => {
return this.surveyAnswers.filter((sa) => {
return fk === sa._id
})
});
console.log('this is surveyAnswerMatches', surveyAnswerMatches)// This is what I get [[{_id:"surveyanswer_2016-11-03T11:48:48Z_1", foo: "someotherbar"}]]
console.log('this.surveyAnswers', this.surveyAnswers)// [{_id:"surveyanswer_2016-11-02T13:29:26Z_1", foo: "bar"}, {_id:"surveyanswer_2016-11-02T15:34:41Z_1", foo: "somebar"},{_id:"surveyanswer_2016-11-03T11:48:48Z_1", foo: "someotherbar"}]
Simply use a closure to access a variable you defined before calling the mapping and forEach:
let surveyAnswerMatches = [];
this.selectedIaReportDiscussedTopic$
.map((discussionTopic) => {return discussionTopic.fk_surveyanswer}) //["string"]
.forEach((fk) => {
surveyAnswerMatches.push(this.surveyAnswers.filter((sa) => {
return fk === sa._id;
}));
});
console.log('this is surveyAnswerMatches', surveyAnswerMatches);
Edit: cleaned up the code
How come the return value does not get assigned to _fk?
Because the return value of the callback you pass into forEach has absolutely nothing to do with what forEach returns (which is nothing, so using its return value gives you undefined).
You've said you want to use "the return value," but which one? The callback is called repeatedly, once for each entry in the array.
You could change your forEach to another map, which would mean you'd end up with an array containing the surveyAnswerMatches for each entry in the array.

Categories

Resources