Cannot read property 'length' of undefined despite check for undefined - javascript

I'm writing some code to generate JSX based on items in an array, however I'm getting the error 'Cannot read property 'length' of undefined' despite having checks in place to see whether the variable is actually undefined. The code is really long so I've summarised the problem here:
render() {
var metadata = this.props.data["metadata"]
if(typeof metadata !== undefined && metadata.length !== undefined) {
for(var i=0; i<metadata.length; i++) {
console.log(metadata[i]);
}
}
}
The render method is inside a component, which is placed inside another, by doing
<Marksheet data={this.state.data} />
I've checked to make sure that data is actually defined and being supplied as a prop, but even if it was undefined, I don't understand why it's saying cannot read property length of undefined.

You could also use the Array.isArray method:
render() {
var metadata = this.props.data["metadata"];
if(Array.isArray(metadata)) {
metadata.forEach(val => console.log(val));
}
}

The string "undefined" is not the same as undefined.
Try changing your code to the following:
render() {
var metadata = this.props.data["metadata"]
if(metadata !== undefined && metadata.length !== undefined) {
for(var i=0; i<metadata.length; i++) {
console.log(metadata[i]);
}
}
}
That basically checks to ensure both metadata and metadata.length are not equal to undefined before running that for loop.

Or just simply. You might also check for metadata.length >0 (instead of just length)
render() {
var metadata = this.props.data["metadata"]
if(metadata && metadata.length) {
for(var i=0; i<metadata.length; i++) {
console.log(metadata[i]);
}
}
}

Related

Cannot read property 'includes' of undefined

I am new to JavaScript, am I was trying to dissect an embedded message. Here's my code, it runs fine for a few mins, works accordingly but idk what goes wrong.
bot.on('message', (message) => {
for (var i = 0; i < message.embeds.length; i++) {
if (message.embeds[i].title.includes("text!")) {
message.channel.send('reply')
}
}
})
Its because there is at least one item inside the embeds array items that missing the title property.
You will need to update the if statement to be:
If (message.embeds[i] &&
message.embeds[i].title && ...)
I think this code can fix this problem.
bot.on('message', (message) => {
for (var i = 0; i < message.embeds.length; i++) {
if (message.embeds[i] && message.embeds[i].title.includes("text!")) {
message.channel.send('reply')
}
}
})
It means inside message.embeds[i] there is at least one element without title property.
You should check first if message.embeds[i].title exists and perform other operations after the check.
You can write your code more defensive like this. Instead of
if(message.embeds[i].title.includes("text!"))
you can write the following
if(typeof message.embeds[i].title === "string" &&
message.embeds[i].title.includes("text!"))
Probably some of the embed object is coming without the title property.
You can safely use your logic changing your if condition to:
if ('title' in message.embeds[i] && message.embeds[i].title.includes("text!")) {
/* ... */
}
JavaScript is not a type safe language, and the error is caused by not being type safe. We will have to check if object exists and nested properties exists and after we should be able check the value. In your case:
bot.on('message', (message) => {
// check if main obj and main property exist
if (message && message.embeds) {
for (var i = 0; i < message.embeds.length; i++) {
// now, check if title exists and after check the text inside
if (
message.embeds[i].title &&
message.embeds[i].title.includes("text!"))
{
message.channel.send('reply')
}
}
}
});
its null pointer error. some of your object parameter is null but its mapped in html. Please try to add more null checks to avoid this .
always check an item before accessing it
bot.on('message', (message) => {
for (var i = 0; i < message.embeds.length; i++) {
if (message.embeds[i].title && message.embeds[i].title.includes("text!")) {
message.channel.send('reply')
}
}
})

Setting property to be null again within Class

I have a class called MapFilter, which conditionally creates an array of objects.
When the class is created, the property named postCodeFilter is automatically set to be null. When using the class with this initial null value the logic works fine:
MapFilter.prototype.filterByPostcode = function(res){
var newRes = [];
console.log(this.postcodeFilter);
if(typeof this.postcodeFilter !== 'undefined') {
for( var i = 0; i < res.length; i++ ) {
if(res[i].postcode == this.postCodeFilter) {
newRes.push(res[i]);
}
}
} else {
newRes = res.slice();
}
return newRes;
};
When it is initially running the method that calls this method, it will run what is in the else block
HOWEVER
after setting a value for postcodeFilter I can not set it back to be null or undefined again.
I have tried the following approaches, with no success
delete this.serviceFilter;
this.serviceFilter = null;
this.serviceFilter = undefined;
I have tried doing the same on the instance of the MapFilter class to no avail
How do I reset a property of a class to be null or undefined again?
function MapFilter (){
this.postcodeFilter=null
}
MapFilter.prototype.filterByPostcode = function(){
console.log(this.postcodeFilter);
if(this.postcodeFilter !== null) {
console.log('is bull')
} else {
console.log('is null')
}
}
var test = new MapFilter()
test.filterByPostcode()
test.postcodeFilter='bull'
test.filterByPostcode()
dont use type of null it will not return null
if you calling prototype inside function
dont call with this.postcodeFilter try use instance name like test.postcodeFilter

How to resolve TypeError: Cannot convert undefined or null to object

I've written a couple of functions that effectively replicate JSON.stringify(), converting a range of values into stringified versions. When I port my code over to JSBin and run it on some sample values, it functions just fine. But I'm getting this error in a spec runner designed to test this.
My code:
// five lines of comments
var stringify = function(obj) {
if (typeof obj === 'function') { return undefined;} // return undefined for function
if (typeof obj === 'undefined') { return undefined;} // return undefined for undefined
if (typeof obj === 'number') { return obj;} // number unchanged
if (obj === 'null') { return null;} // null unchanged
if (typeof obj === 'boolean') { return obj;} // boolean unchanged
if (typeof obj === 'string') { return '\"' + obj + '\"';} // string gets escaped end-quotes
if (Array.isArray(obj)) {
return obj.map(function (e) { // uses map() to create new array with stringified elements
return stringify(e);
});
} else {
var keys = Object.keys(obj); // convert object's keys into an array
var container = keys.map(function (k) { // uses map() to create an array of key:(stringified)value pairs
return k + ': ' + stringify(obj[k]);
});
return '{' + container.join(', ') + '}'; // returns assembled object with curly brackets
}
};
var stringifyJSON = function(obj) {
if (typeof stringify(obj) != 'undefined') {
return "" + stringify(obj) + "";
}
};
The error message I'm getting from the tester is:
TypeError: Cannot convert undefined or null to object
at Function.keys (native)
at stringify (stringifyJSON.js:18:22)
at stringifyJSON (stringifyJSON.js:27:13)
at stringifyJSONSpec.js:7:20
at Array.forEach (native)
at Context.<anonymous> (stringifyJSONSpec.js:5:26)
at Test.Runnable.run (mocha.js:4039:32)
at Runner.runTest (mocha.js:4404:10)
at mocha.js:4450:12
at next (mocha.js:4330:14)
It seems to fail with:
stringifyJSON(null) for example
Generic answer
This error is caused when you call a function that expects an Object as its argument, but pass undefined or null instead, like for example
Object.keys(null)
Object.assign(window.UndefinedVariable, {})
As that is usually by mistake, the solution is to check your code and fix the null/undefined condition so that the function either gets a proper Object, or does not get called at all.
Object.keys({'key': 'value'})
if (window.UndefinedVariable) {
Object.assign(window.UndefinedVariable, {})
}
Answer specific to the code in question
The line if (obj === 'null') { return null;} // null unchanged will not
evaluate when given null, only if given the string "null". So if you pass the actual null value to your script, it will be parsed in the Object part of the code. And Object.keys(null) throws the TypeError mentioned. To fix it, use if(obj === null) {return null} - without the qoutes around null.
Make sure that object is not empty (null or undefined ).
Error:
let obj
Object.keys(obj)
Solution:
Object.keys(obj || {})
Make sure that destination object is not empty ( null or undefined ).
You can initialize destination object with empty object like below:
var destinationObj = {};
Object.assign(destinationObj, sourceObj);
This is very useful to avoid errors when accessing properties of null or undefined objects.
null to undefined object
const obj = null;
const newObj = obj || undefined;
// newObj = undefined
undefined to empty object
const obj;
const newObj = obj || {};
// newObj = {}
// newObj.prop = undefined, but no error here
null to empty object
const obj = null;
const newObj = obj || {};
// newObj = {}
// newObj.prop = undefined, but no error here
Adding Object && works before putting the object on to map.
objexts && Object.keys(objexts)?.map((objext, idx) =>
In my case, I added Lucid extension to Chrome and didn't notice the problem at that moment. After about a day of working on the problem and turning the program upside down, in a post someone had mentioned Lucid. I remembered what I had done and removed the extension from Chrome and ran the program again. The problem was gone. I am working with React. I thought this might help.
I solved the same problem in a React Native project. I solved it using this.
let data = snapshot.val();
if(data){
let items = Object.values(data);
}
else{
//return null
}
Replace
if (typeof obj === 'undefined') { return undefined;} // return undefined for undefined
if (obj === 'null') { return null;} // null unchanged
with
if (obj === undefined) { return undefined;} // return undefined for undefined
if (obj === null) { return null;} // null unchanged
If you're using Laravel, my problem was in the name of my Route.
Instead:
Route::put('/reason/update', 'REASONController#update');
I wrote:
Route::put('/reason/update', 'RESONController#update');
and when I fixed the controller name, the code worked!
In my case I had an extra pair of parenthesis ()
Instead of
export default connect(
someVariable
)(otherVariable)()
It had to be
export default connect(
someVariable
)(otherVariable)
Below snippet is sufficient to understand how I encountered the same issue but in a different scenario and how I solved it using the guidance in the accepted answer. In my case I was trying to log the keys of object present in the 0th index of the 'defaultViewData' array using Object.keys() method.
defaultViewData = [{"name": "DEFAULT_VIEW_PLP","value": {"MSH25": "LIST"}}]
console.log('DEFAULT_VIEW', Object.keys(this.props.defaultViewData[0]));
The console.log was not getting printed and I was getting the same error as posted in this question. To prevent that error I added below condition
if(this.props.defaultViewData[0]) {
console.log('DEFAULT_VIEW', Object.keys(this.props.defaultViewData[0]));
}
Adding this check ensured that I didn't get this error. I hope this helps for someone.
Note: This is React.js code. (although to understand the problem it doesn't matter).
reactTraverser.js:6 Uncaught TypeError: Cannot convert undefined or null to object at Function.keys () at reactTraverser.js:6
If you are getting this error on typeScript Try using it without Live Server this error will not be displayed
I have the same problem with a element in a webform. So what I did to fix it was validate.
if(Object === 'null')
do something

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.

Possible to ignore Cannot read property '0' of undefined? [duplicate]

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.

Categories

Resources