Get rid of `undefined` in a array of objects - javascript

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

Related

Firestoreb collection foreach loop returns empty id

in my collection (Campaign), I want to return a specific document id by a campaignName
this is my method :
getCampaignId(): string {
const campaignCollection = this.afs
.collection<Campaign>('mail_campaign')
.snapshotChanges();
campaignCollection.forEach((value) => {
return value.map((res) => {
if (res.payload.doc.data().campaignName === 'x') {
this.campaignId = res.payload.doc.id;
}
return '';
});
});
return this.campaignId;
}
inside the if , I get the id if I print it directly in the console :
console.log(res.payload.doc.id);
but if I print my global variable this.campaignId in the constructor, I get an empty string (the method is called in the constructor before printing the variable in the console)
I want to use this variable outside of this class, but I can't because it's returning an empty string.
Any ideas ?

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

Getting error Uncaught TypeError: Cannot read property 'toLowerCase' of undefined

Getting error Uncaught TypeError: Cannot read property 'toLowerCase' of undefined
while executing this code.
const map = (array, callback) => {
return [callback(array[0])].concat(map(array.slice(1),callback));
}
var lower = map(['A','B','C'],function (val) {
return val.toLowerCase()
});
console.log(lower);
You need to check if array length is 1 then only return the element because there are no other elements left.
const map = (array, callback) => {
if(array.length === 1) return [callback(array[0])]
return [callback(array[0])].concat(map(array.slice(1),callback));
}
var lower = map(['A','B','C'],function (val) {
return val.toLowerCase()
});
console.log(lower);
It seems that you want to create your own map(). In think you loop is better than recursion.
const map = (array, callback) => {
let res = []
for(let i = 0;i<array.length;i++){
res[i] = callback(array[i],i)
}
return res;
}
var lower = map(['A','B','C'],function (val) {
return val.toLowerCase()
});
console.log(lower);
Why OP's code donot work?
The code in question uses recursion. And whenever we use recursive approach we should have a condition to return the function with calling it again.
Now consider then the array length is 1
then array.slice(1) will return []
an empty array will be passed to map().
For an empty array array[0] will `undefined
then undefined will be passed to callback
undefined.toLowerCase throws error.
Conclusion
You don't need to run the part .concat(map(array.slice(1),callback)) when only one element is left in array. Because there is noting more to concat()

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

AngularJS .length returns a TypeError

I'm performing a very routine task in my Filter to check if
angular.module('someApp')
.filter('filterSomeData',['$filter',function ($filter) {
return function (items, keyObj) {
var filterObj = {
data:items,
filteredData:[],
applyFilter : function(query,key){
var fData = [];
//unfiltered data at the start
if(this.filteredData.length === 0){
this.filteredData = this.data;
}
if(query){
var fObj = {};
if(!angular.isArray(query)){
fObj[key] = query;
angular.forEach(fObj, function(fObj, i){
fData = fData.concat(
$filter('filter')
(this.filteredData,fObj));
}, this);
console.log(this.filteredData);
}
else if(angular.isArray(query)){
console.log(query);
if(query.length > 0){
for(var i=0;i<obj.length;i++){
if(angular.isDefined(query[i])){
fObj[key] = query[i];
angular.forEach(fObj, function(fObj, i){
fData = fData.concat(
$filter('filter')
(this.filteredData,fObj));
}, this);
}
}
}
}
if(fData.length > 0){
this.filteredData = fData;
}
else{
this.filteredData;
}
}
}
};
if(keyObj){
angular.forEach(keyObj,function(query,key){
filterObj.applyFilter(query,key);
});
}
return filterObj.filteredData;
}
}])
But in my console it fires an error:
TypeError: Cannot read property 'length' of undefined
Even if we assume this.filteredData isn't defined at the time when checked, I cannot understand why .length fires an error.
The functionality isn't affected at all but I want to make sure my console is clean.
Any ideas?
Update:
Diving deeper into the code, it looks like the filters are applied before the AJAX call is complete. Initially filterObj is undefined and then populates as soon as the data is loaded. Is there a way to delay the injection of filters until the data is loaded, like a promise?
Thanks for your time!
Even if we assume this.filteredData isn't defined at the time when
checked, I cannot understand why .length fires an error.
If you try to access a property on an object that is not defined, then you get this type error. Try this at the console:
a = {b:'four'}
a.b.length
4
a.c.length
Uncaught TypeError: Cannot read property 'length' of undefined
Therefore if this.filteredData does not exist, you cannot access the length property.
I world find out why the element is undefined, and maybe declare it AS an empty object or array somewhere before the If statement.

Categories

Resources