I'm trying to cut down on my verbose classList.add('lorem') calls. I can easily add the same class to multiple created elements like so:
const loremDiv = document.createElement('div'), ipsumDiv = document.createElement('div')
loremDiv.classList.add('hi')
ipsumDiv.classList.add('hi')
But when I try to add the class via a single forEach like so:
[loremDiv,ipsumDiv].forEach((el) => {
el.classList.add('hi')
}
I get the following error:
TypeError: Cannot read properties of undefined (reading 'forEach')
As others have mentioned, you are missing vital semi-colons. Both Felix and Pointy make valid points. There is really no need to omit semi-colons. It may look more hip and modern, but it will bite you down the road and cause cryptic errors like this.
Fails
The document.createElement call returns an element, but since you did not include a semi-colon, it runs into the next line like so:
document.createElement('div')[loremDiv, ipsumDiv]
Since you did not terminate the ipsumDiv assignment, the interpreter is complaining that it was not assigned already.
As for the forEach((el) => el.classList.add('hi')) call, Array.prototype.forEach returns nothing, so you are calling loremDiv on an undefined object.
forEach((el) => el.classList.add('hi'))[loremDiv, ipsumDiv]
const
loremDiv = document.createElement('div'),
ipsumDiv = document.createElement('div') // Missing semi-colon!
// "Uncaught ReferenceError: Cannot access 'ipsumDiv' before initialization"
[loremDiv, ipsumDiv].forEach((el) => el.classList.add('hi')) // Missing semi-colon!
// "Uncaught TypeError: Cannot read properties of undefined (reading '#<HTMLDivElement>')"
[loremDiv, ipsumDiv].forEach((el) => document.body.append(el)) // Optional semi-colon
.hi:before { content: "HI!" }
Working
const
loremDiv = document.createElement('div'),
ipsumDiv = document.createElement('div'); // Semi-colon required
[loremDiv, ipsumDiv].forEach((el) => el.classList.add('hi')); // Semi-colon required
[loremDiv, ipsumDiv].forEach((el) => document.body.append(el)); // Why not add one?
.hi:before { content: "HI!" }
Related
const quoteText = document.querySelector("quote")
quoteBtn = document.querySelector("button")
// random quote function
function randomQuote() {
//Fetching random quote from API and parsing it into Js Object
fetch("https://api.quotable.io/random").then(res => res.json()).then(result=>{
console.log(result);
quoteText.innerText = result.content;
});
}
quoteBtn.addEventListener("click", randomQuote);
I expect it to next the quote as i am clicking on it, but rather it is displaying in the console as "Uncaught (in promise) TypeError: Cannot set properties of null (setting 'innerText')"
It looks like you are trying to fetch a random quote from an API and display it on a website when a button is clicked.
There's a syntax error in the code, the quoteBtn declaration is missing a var or const keyword, which should be fixed:
const quoteText = document.querySelector("quote");
const quoteBtn = document.querySelector("button");
Additionally, make sure that the elements with the quote and button class names actually exist in your HTML, otherwise quoteText and quoteBtn will be null and the code will throw an error when trying to add the click event listener.
If you use document.querySelector(), you need to use a class or an id, unless your target is a native html element. <quote> is not a native html element. So I guess you need to use:
const quoteText = document.querySelector(".quote")
Mind the . in document.querySelector(".quote")
I am using angularFireStorage (in my Ionic app).
I am having some success, for instance, I can look at my console.log(res) to click the link in my console to view a belt image. I cannot save it to a variable however, which is the issue. Ultimately I would like to use the image tag and link the belt image using src. Here is my code:
const ref = this.storage.ref('belts/');
ref.listAll().subscribe(belt=>
belt.items.forEach(item=> printImage(item))
)
function printImage(imageRef){
let temp = imageRef.getDownloadURL();
temp.then(res=> {
console.log(res)
this.mySRCs.push(res)
})
}
and how I am testing it.
<img [src]="sanitizer.bypassSecurityTrustResourceUrl(mySRCs[0])"/>
and the error:
Uncaught (in promise): TypeError: Cannot read property 'mySRCs' of undefined
TypeError: Cannot read property 'mySRCs' of undefined
I feel like I did something similar a month or two ago but this time I cannot see the image in my app. Thanks for your help.
I think your issue is with using the 'this' keyword within your 'printImage' function.
You either need to do:
belt.items.forEach(item=> printImage.bind(this, item))
or assuming you have a...
const mySRCs = [];
then you just pass the field as an argument to the printImage function...
belt.items.forEach(item=> printImage(item, mySRCs))
and instead of using 'this' inside the function, you use...
function printImage(imageRef, mySRCs){
let temp = imageRef.getDownloadURL();
temp.then(res=> {
console.log(res)
mySRCs.push(res) //<--- remove this
})
}
I am writing code in plain JavaScript, there are lot of scenarios where I will use querySelector() method, I ran into issue multiple times like
"Uncaught TypeError: Cannot read property 'classList' of null" for the following code,
document.querySelector('.tab.active').classList.remove('active');
/** Tab not available at the time**/
In Jquery $('.tab.active').removeClass('active'); will run only if the element is available without throwing error.
I want to achieve similar behavior in JavaScript. Please provide your ideas.
I am not willing to write three lines of code for every DOM operation I am doing, looking for one line code like Jquery.
var activeTab = document.querySelector('.tab.active');
if(activeTab !== 'null' ){
activeTab.classList.remove('active');
}
Explicitly checking for the existence of the element in your code as you're doing originally is surely the clearest way you could do it, but if you really don't want to, you could create your own function that, if no element is found, returns an object with methods that don't do anything. For example:
const customQS = selector => (
document.querySelector(selector)
|| {
classList: {
remove: () => void 0
}
}
);
customQS('.tab.active').classList.remove('active');
console.log('done, no error');
Of course, with that method, you'd have to create properties for each DOM method you'd want to use. A more robust option would be to actually create an element and return it, which would be more expensive, but the element will be garbage collected right afterward:
const customQS = selector => (
document.querySelector(selector)
|| document.createElement('div')
);
customQS('.tab.active').classList.remove('active');
console.log('done, no error');
let nasPath = "";
return getFamInfo(args.familyID)
.then(function (famInfo) {
nasPath = //some code involving famInfo here
return getSFTPConnection(config.nasSettings);
}).then(function (sftp) {
const fastPutProm = Promise.promisify(sftp.fastPut);
return fastPutProm(config.jpgDirectory, nasPath, {});
});
If I put a breakpoint after const fastPutProm = Promise.promisify(sftp.fastPut);, fastPutProm is a function with three arguments. But when I try to run this code, I get a TypeError: Cannot read property 'fastPut' of undefined error. What am I doing wrong here?
That error means that your sftp value is undefined so when you try to pass sftp.fastPut to the promisify() method, it generates an error because you're trying to reference undefined.fastPut which is a TypeError.
So, the solution is to back up a few steps and figure out why sftp doesn't have the desired value in it.
Another possibility is that the error is coming from inside the module and it's because the implementation of sftp.fastPut is referencing this which it expects to be sftp. Your method of promisifying is not preserving the value of this. You can fix that by changing your code to:
const fastPutProm = Promise.promisify(sftp.fastPut, {context: sftp});
PROBLEM: When inheriting an object's properties and methods, a child object seems to loose connection with parent's 'this'. To illustrate it better, look at my example:
function RigidBody() {
this.local = new Matrix4x3();
this.position = new vec3();
...
}
RigidBody.prototype = {
...
setPosition: function(vec) {
this.position.copy(vec);
this.local.setTranslation(this.position);
}
...
};
CameraObject.prototype = new RigidBody();
CameraObject.prototype.constructor = CameraObject;
function CameraObject() {
this.fov = ...
}
CameraObject.prototype.add = ...;
var camera = new CameraObject();
camera.add(...); // Works fine;
camera.setTranslation(...); // Throws "TypeError: Cannot read property 'setTranslation' of undefined
// And on another PC it throws: "http://localhost:8080/js/rigidBody.js(61): Uncaught exception: TypeError: Cannot convert 'this.local' to object"
How to bypass it? I found a workaround for this problem by assigning this.this = this; to parental object and replacing every this by this.this. Unfortunately as a result I need to add .this to every camera function call like this: camera.this.setPosition(...);
as a general advice, please add console.log(camera) to your code and inspect the object in a good browser console, I highly recommend Firebug
that way you can explore what properties and nested properties are available to camera object
from your code example in original question, setTranslation appears to be a property of camera.local, not camera itself.
or perhaps you wanted to call camera.setPosition(...); given that you added it to RigidBody's prototype, but never used it afterwards - jsfiddle?
and given the code provided in comment below:
function Matrix4x3(){
this.element = new Float32Array(16);
}
which does not define setTranslation, so this.local.setTranslation might be undefined as well..
You need to call "super", in other words, inherit the properties from the parent constructor:
function CameraObject() {
RigidBody.call(this); // inherit RigidBody properties
this.fov = ...
}