https://developer.mozilla.org/en-US/docs/Web/Events
https://gitlab.com/snippets/1820469
Found out about the Fetch API today. I've been using XMLHTTPRequests for too long! Docs here.
Here's a quick example:
document.getElementById('fileUploadForm').onsubmit = async (e) => {
e.preventDefault();
let response = await fetch(window.origin + '/forms/templateimport/', {
method: 'POST',
body: new FormData(document.getElementById('fileUploadForm')),
'Content-Type': 'application/json',
headers: {
'X-CSRFToken': Cookies.get('csrftoken'),
},
});
let result = await response.json();
drawFields(result.fields);
}
new Date(Date.parse('2020-05-01')).toLocaleDateString()
>>> "4/30/2020"
See the problem? As per this article, it's much better to do something like this:
/* @param {string} s - an ISO 8001 format date and time string
** with all components, e.g. 2015-11-24T19:40:00
** @returns {Date} - Date instance from parsing the string. May be NaN.
*/
function parseISOLocal(s) {
var b = s.split(/\D/);
return new Date(b[0], b[1]-1, b[2], b[3], b[4], b[5]);
}
document.write(parseISOLocal('2015-11-24T19:40:00'));
Or, if you're just working with dates:
function parseDate(s) {
var b = s.split(/-/);
return new Date(b[0], b[1]-1, b[2]);
}
https://stackoverflow.com/questions/6419128/javascript-for-loop-variable-and-recursion
Cache the length of the array so you would have the following:
function recurse(node) { for(var i = 0, count = node.children.length; i < count; i++) { recurse(node.children[i]); } }
You should always cache especially when you're dealing with HTMLCollections.
Just another note from me: the "count" variable needs to be unique from other "count" variables used on other loops within the same function.
Note: It may be more worthwhile to use the foreach
method on an array. It's easier to read and I think could simplify the code.
https://flaviocopes.com/javascript-sleep/
Create the sleep function:
const sleep = (milliseconds) => {
return new Promise(resolve => setTimeout(resolve, milliseconds))
}
Use the sleep function:
sleep(500).then(() => {
//do stuff
})
Or use it in an async function:
const doSomething = async () => {
await sleep(2000)
//do stuff
}
doSomething()
Remember that due to how JavaScript works (read more about the event loop), this does not pause the entire program execution like it might happen in other languages, but instead only your function sleeps.
Sometimes you have a large anchor tag containing some extra buttons that you'd like to have fire off a JavaScript function, while not navigating away from the page. Just add return false
to the end of your onclick
statement!
<a href="#">
text here
<i class="material-icons copyButton" onclick="copyToClipboard('thisText');return false;">
</a>
Say you have a div, which has an onclick property (maybe highlights a card or something). That function might reveal buttons inside the div, with their own onclick properties. How do you prevent the parent's onclick from executing when clicking one of the child buttons? You add the following to the beginning of the child's onclick attribute: event.stopPropagation();
.
For example:
<div class="card cardSelected" onclick="selectCard(this);">
<div class="button deleteButton" onclick="event.stopPropagation();deleteObject('{id}');">Delete</div>
<div class="button cancelButton" onclick="event.stopPropagation();showEditControls(this.parentNode.parentNode);">Cancel</div>
<div class="button saveButton" onclick="event.stopPropagation();saveObject('{id}');">Save</div>
</div>
yourdiv.scrollIntoView({behavior: "smooth", block:"end", inline:"nearest"});
https://stackoverflow.com/q/26848289/2887850
It's time to start using querySelector
and querySelectorAll
! They are both fully supported, utilize existing CSS syntax and are shorter to type (yay!).
UPDATE: Looks like it has worse performance, as per this question. Probably better off to keep using getElementById
and getElementsByClassName
for that extra bit of performance.
UPDATE 2020-07-08: After a long time thinking and looking at querySelector, I've gotta say the benefits of the cleaner code sure come close to making it worth it. It sure seems to be picking up steam. Maybe I'll use it a little more for now, see how bad the performance hit really is...
HTML data-attributes are pretty limited. They are just strings! And clutter your DOM. Why not create JS classes that inherit from HTML DOM objects, and put your complex data (including objects) there? Recommended to pair this with methods to get the properties, and events to trigger the methods. Something to think about.
https://itnext.io/handling-data-with-web-components-9e7e4a452e6e
Keep in mind:
premature optimisation is the root of all evil. measure first. optimise later.
https://medium.com/hackernoon/3-javascript-performance-mistakes-you-should-stop-doing-ebf84b9de951
For Loop, average loop time: ~10 microseconds
For-Of, average loop time: ~110 microseconds
ForEach, average loop time: ~77 microseconds
While, average loop time: ~11 microseconds
Reduce, average loop time: ~113 microseconds
HTML:
<div class="btn btn-danger" onclick="outsideResolve(false);">Cancel</div>
<div class="btn btn-success" onclick="outsideResolve(true);">Continue</div>
JS:
var outsideResolve;
async function awaitUserInput() {
let promise = new Promise(function (resolve) {
outsideResolve = resolve;
});
var output = await promise;
return output;
}
let userHitContinue = await awaitUserInput();
console.log(userHitContinue);
myResult = ( function() {return 'a';} ) ();
var loadedPdf; // Used for releasing the loaded PDF
async function getPdf(url, target) {
if (loadedPdf) { window.URL.revokeObjectURL(loadedPdf) };
let response = await fetch(url, { method: 'GET' });
loadedPdf = await response.blob();
document.querySelector(target).setAttribute('data', window.URL.createObjectURL(loadedPdf));
};