document.querySelectorAll('#myTable td')
.forEach(e => e.addEventListener("click", function() {
// Here, `this` refers to the element the event was hooked on
console.log("clicked")
}));This creates a separate function for each cell; instead, you could share one function without losing any functionality.
function clickHandler() {
// Here, `this` refers to the element the event was hooked on
console.log("clicked")
}
document.querySelectorAll('#myTable td')
.forEach(e => e.addEventListener("click", clickHandler));Example
var hover = document.querySelectorAll('.hover');
// The functions are cointained inside another one to prevent execution on load.
hover.forEach(e => e.addEventListener("mouseover", () => mouseOver(e)));
hover.forEach(e => e.addEventListener("mouseout", () => mouseOut(e)));
function mouseOver(e) {
e.classList.remove("w3-black");
e.classList.add("w3-teal");
}
function mouseOut(e) {
e.classList.remove("w3-teal");
e.classList.add("w3-black");
}Submitting a form registers an event for a split second and it vanishes. In order to prevent that and make it persistent, we need to use the event method preventDefault() i.e. it stops the normal form submission to a file.
form.addEventListener("submit", runEvent);
function runEvent(e){
e.preventDefault();
console.log(e.target.value); // Logs out the input value. Or selector value.
}Going over a promise step-by-step.
- First, try a pure
fetch:
fetch('https://jsonplaceholder.typicode.com/users')
>>> Promise {<pending>}- Now output the raw response
fetch('https://jsonplaceholder.typicode.com/users')
.then(response => console.log(response))
>>> Promise {<pending>}
>>> Response {type: "cors", url: "https://jsonplaceholder.typicode.com/users", redirected: false, status: 200, ok: true, …}
> body: ReadableStream
> bodyUsed: false
> headers: Headers {}
> ok: true
> redirected: false
> status: 200
> statusText: ""
> type: "cors"
> url: "https://jsonplaceholder.typicode.com/users"
> __proto__: Response- Now convert the response to json.
fetch('https://jsonplaceholder.typicode.com/users')
.then(response => response.json())
>>> Promise {<pending>}- Now output the json data.
fetch('https://jsonplaceholder.typicode.com/users')
.then(response => response.json())
.then(data => console.log(data))
>>> Promise {<pending>}
>>> (10) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]A promise starts working the moment it is created. The .then is to process the output.
const promise = new Promise((resolve, reject) => {
if (true) {
resolve('Stuff worked')
} else {
reject('Error, it broke')
}
})
promise
.then(result0 => result0 + '!')
.then(result1 => {
console.log(result1);
return result1 + '?'
})
.then((result2) => console.log(result2 + '...'))
.then(() => {
//result2 is lost cuz no return statement was present above
//so no use of accepting arguments to this f()
console.log('Dont mind me')
})
.catch(() => {
//only runs for errors occuring before it
console.log('Error!')
})
.then(result3 => {
//result3 is undefined
throw Error('Oops result is lost here.');
console.log(result3 + '?') // line won't run cuz of throw Error above
})
.catch((e) => {
//if error is not caught, promise is rejected
console.log('Error at the end: ' + e)
})Output:
if(true)
Stuff worked!
Stuff worked!?...
Dont mind me
Error at the end: Error: Oops result is lost here.
Promise {<resolved>: undefined}if(false)
Error!
Error at the end: Error: Oops result is lost here.
Promise {<resolved>: undefined}Promises can be made separate and run together.
Only the variables take time to get their values. Not Promise.all(). It's just there to process it. It will only work when all have been resolved/rejected, but not pending. So if you run the variables and then after some time, do the Promise.all, it will run instantly cuz all variables will have been executed and will just be waiting to be processed.
const promise0 = new Promise((resolve, reject) => {
resolve('Stuff Worked')
})
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'HII');
})
const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 'Pookie');
})
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Looking for me?');
}, 3000);
})
Promise.all([promise0, promise1, promise2, promise3])
.then(values => {
console.log(values);
})Output:
>>> Promise {<pending>}
>>> (4) ["Stuff Worked", "HII", "Pookie", "Looking for me?"]
> 0: "Stuff Worked"
> 1: "HII"
> 2: "Pookie"
> 3: "Looking for me?"
> length: 4
> __proto__: Array(0)- Create a promise that resolves in 4 seconds and returns "success" string
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("success");
}, 4000)
});- Run the above promise and make it console.log "success"
promise.then(console.log)
// or
promise.then(resp => console.log(resp))- Read about
Promise.resolve()andPromise.reject(). How can you make the above promise shorter withPromise.resolve()and console loggin "success"
const promise = Promise.resolve(
setTimeout(() => {
console.log("success");
}, 4000)
);- Catch this error and console log 'Ooops something went wrong'
Promise.reject('failed')
.catch((e) => console.log('Ooops something went wrong' + e))- Use Promise.all to fetch all of these people from Star Wars (SWAPI) at the same time. Console.log the output and make sure it has a catch block as well.
const urls = [
'https://swapi.co/api/people/1',
'https://swapi.co/api/people/2',
'https://swapi.co/api/people/3',
'https://swapi.co/api/people/4'
]
Promise.all(urls.map(url =>
fetch(url).then(people => people.json())
))
.then(array => {
console.log('1', array[0])
console.log('2', array[1])
console.log('3', array[2])
console.log('4', array[3])
})
.catch(err => console.log('ughhhh fix it!', err));- Change one of your urls above to make it incorrect and fail the promise. Does your catch block handle it?
Yes. Only that wrong url will throw error. rest will work.Example 1:
Old method: [ES2015/ES6] Assume a fetch that returns a promise.
fetch('https://jsonplaceholder.typicode.com/users')
.then(response => response.json())
.then(data => console.log(data))New method: [ES2017/ES8] Async await is a syntactic sugar.
// use async to let js know we using async await
async function fetchUsers(){
const response = await fetch('https://jsonplaceholder.typicode.com/users'); // pause till this await works
const data = await response.json(); //then pause till this await works
console.log(data);
}
fetchUsers(); // run itExample 2:
Let these be the URLs
const urls = [
'https://jsonplaceholder.typicode.com/users',
'https://jsonplaceholder.typicode.com/posts',
'https://jsonplaceholder.typicode.com/albums'
]Old method: [ES2015/ES6] Multiple URLs being handled in one Promise. if any url is wrong, or an error is thrown, it will be handled only for that url.
Promise.all(urls.map(url => {
return fetch(url).then(resp => resp.json())
})).then(results => {
console.log(results[0])
console.log(results[1])
console.log(results[2])
}).catch((e) => console.log('error'))
alert(0) // will run earliestThe above will output all of the urls. But in the meanwhile, the program will proceed ahead and alert(0) will run as usual.
New method: [ES2017/ES8]
const getData = async function() {
try {
const [ users, posts, albums ] = await Promise.all(urls.map(url =>
fetch(url).then(resp => resp.json())
))
console.log('Users', users)
console.log('Posts', posts)
console.log('Albums', albums)
} catch (err) {
console.log('Oops', err)
}
}
getData()Newer method: [ES2018/ES9] Await-of feature, using for of.
// Basic for-of example
const loopThroughUrl = (urls) => {
for (url of urls) {
console.log(url)
}
}In below case, for-await takes each item from the array and waits for it to resolve. You'll get the first response even if the second response isn't ready yet, but you'll always get the responses in the correct order.
Using for-of on previous code example.
const getData2 = async function () {
const arrayOfPromises = urls.map(url => fetch(url));
for (const request of arrayOfPromises) {
console.log(request);
}
for await (const request of arrayOfPromises) {
const data = await request.json();
console.log(data)
}
}
getData2()const urls = [
'https://swapi.co/api/people/1',
'https://swapi.co/api/people/2',
'https://swapi.co/api/people/3',
'https://swapi.co/api/people/4'
]
Promise.all(urls.map(url => fetch(url).then(people => people.json())))
.then(array => {
throw Error
console.log('1', array[0])
console.log('2', array[1])
console.log('3', array[2])
console.log('4', array[3])
})
.catch(err => console.log('ughhhh fix it!', err))
.finally(() => console.log('extra action here'))Output
Promise {<pending>}
ughhhh fix it! ƒ Error() { [native code] }
extra action herevar txt = '{"name":"John", "age":30, "city":"New York"}'
var obj = JSON.parse(txt);
document.getElementById("demo").innerHTML = obj.name + ", " + obj.age;Imagine a json response from a file called json_demo.txt, whose output is:
{
"name":"John",
"age":31,
"pets":[
{ "animal":"dog", "name":"Fido" },
{ "animal":"cat", "name":"Felix" },
{ "animal":"hamster", "name":"Lightning" }
]
}Old way of using Ajax and reading the json response:
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var myObj = JSON.parse(this.responseText);
document.getElementById("demo").innerHTML = myObj.name;
}
};
xmlhttp.open("GET", "json_demo.txt", true);
xmlhttp.send();New way:
fetch('json_demo.txt')
.then(response => response.json())
.then(data => document.getElementById("demo").innerHTML = data.age)var obj = { name: "John", age: 30, city: "New York" };
var myJSON = JSON.stringify(obj);
document.getElementById("demo").innerHTML = myJSON;
// Stringified output
// {"name":"John","age":30,"city":"New York"}