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")
Related
Im writing an ReactJs app simulating a text editor for coding. I have a textarea that show the line count, and the other one has all the code that the user will be writing. I've tried using this method:
textEditor.onScroll = (e)=>{
linecount.scrollTop = textEditor.scrollTop;
linecount.scrollLeft = textEditor.scrollLeft;
};
But the browser console throws this error: Uncaught TypeError: can't define property "onScroll": Object is not extensible. I suppose that this happens because both textarea are declared as:
var textEditor = React.createElement("textarea",{id:"textEditor"});
var linecount = React.createElement("textarea",{id:"linecount"});
And not as document.getElementbyid... How could I synchronize the scroll of the textEditor to the linecount?
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!" }
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 want to grab a string that has a particular class name, lets say 'CL1'.
This is what is used to do and it worked:
(we are inside an asycn function)
var counter = await page.evaluate(() => {
return document.querySelector('.CL1').innerText;
});
Now, after some months, when i try to run the code i get this error:
Error: Evaluation failed: TypeError: Cannot read property 'innerText' of null
I did some debugging with some console.log() before and after the previous snippet of code and found out that this is the culprit.
I looked the code of the webpage and the particular class is inside.
But i found out two more classes with the same name.
All three of them are nested deep inside many classes.
So what is the proper way to selected the one i want, given i know the class hierarchy for the one i am interested in?
EDIT:
Since there are three class names with the same name, and i want to extract info from the first, can i use an array notation on the querySelector() to access the information from the first one?
EDIT2:
I run this:
return document.querySelector('.CL1').length;
and i got
Error: Evaluation failed: TypeError: Cannot read property 'length' of null
This gets even more confusing...
EDIT 3:
I trie the suggestion of Md Abu Taher and i saw that the snippet of code he provided did not return undefined. This means that the selector is visible to my code.
Then i run this snippet of code:
var counter = await page.evaluate(() => {
return document.querySelector('#react-root > section > main > div > header > section > ul > li:nth-child(1) > a > span').innerText;
});
And i got back the same error:
Error: Evaluation failed: TypeError: Cannot read property 'innerText' of null
The answer is divided in to parts. Getting right selector, and getting data.
1. Getting right Selector
Use inspect element
Right click on your desired element and click inspect element.
Then right click and click Copy > Copy selector
This will give you a unique selector for that specific element.
Use a selector tool
There are bunch of chrome extension that helps you find the right selector.
Selectorgadget
Get Unique CSS Selector
Copy Css Selector
2. Getting the data
Given your selector is .CL1, you need to do few things.
Wait for all Network events to finish
Basically on a navigation you can wait until network is idle.
await page.goto(url, {waitUntil: 'networkidle2'});
Wait for the element to appear in DOM.
Even if the network is idle, there might be redirect etc. Best choice is to wait until the element appears. The following will wait until the element is found and will throw an error otherwise.
await page.waitFor('.CL1');
Or, Check if element exists and return data only if it exists
If you do not want to throw an error or if the element appears randomly, you need to check it's existence and return data.
await page.evaluate(() => {
const element = document.querySelector('.CL1');
return element && element.innerText; // will return undefined if the element is not found
});
try to verify the element before
var x = document.getElementsByClassName("example");
OR
var x = document.getElementsById("example");
and then
var counter = await page.evaluate(() => {
return x.innerText;
});
I have multiple .home elements and I want to click on the last one
Here is what i wrote:
await page.waitForSelector('.home');
const el = await page.$eval('.home', (elements) => elements[elements.length - 1]);
el.click();
But it does not work. Instead I get the following error:
TypeError: Cannot read property 'click' of undefined
at open_tab (C:\wamp64\www\home_robot\robot.js:43:12)
at process._tickCallback (internal/process/next_tick.js:68:
The easiest way is to use page.$$ to get all element handles of the .home elements and then you click on the last element in the array:
const elements = await page.$$('.home');
await elements[elements.length - 1].click();
Why your code is not working
You cannot use page.$eval to return an element handle because the data you return there will be serialized via JSON.stringify when sending it from the browser to your Node.js environment.
Quote from the docs linked above:
returns: Promise<Serializable> Promise which resolves to the return value of pageFunction
As a DOM element cannot be serialized, you cannot click on it in your Node.js script and you get the error instead. You have to use page.$ or page.$$ to get the element handles.