Skip to content

Instantly share code, notes, and snippets.

@jesperorb
Last active October 23, 2023 14:53
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jesperorb/3975943c4fdc5865d983e2e4df8c0b00 to your computer and use it in GitHub Desktop.
Save jesperorb/3975943c4fdc5865d983e2e4df8c0b00 to your computer and use it in GitHub Desktop.
Pros and cons using .insertAdjacentHTML vs .createElement
/**
* There is a pro to using document.createElement() instead of just applying a
* string to the page that gets converted to HTML. When we use the pure string method
* we do not get a link/reference to the actual element that is seen on the page. This
* usually means we have to get the element again to modify it. For example, add an event
* listener
*/
//-----------------------------------------------
// .createElement() + .addEventListener()
//-----------------------------------------------
const button = document.createElement('button');
button.innerText = 'Click me';
// We can add an eventlistener directly to the element before adding it to the page
button.addEventListener('click', function(){
console.log('I get applied to the element');
});
// Add it as a child of the <body>-tag
document.body.appendChild(button);
//-----------------------------------------------
// .insertAdjacentHTML + .addEventListener()
//-----------------------------------------------
/* In the eyes of JavaScript, this is just a pure string.
* the element created with .createElement on the other hand
* is recognized as an element. This button doesn't become a button
* until we add it to the page.
*/
const button = `<button id="toggleMenu"> Click me</button>`;
doucument.body.insertAdjacentHTML('afterbegin', button);
/*
* We need to get the element from the page again if we want to manipulate it
* and if we want to get the element from the page, we need to have some sort of
* identifier. In this case I added a id to easily get it from the page.
*/
const toggleMenuButton = document.querySelector('#toggleMenu');
toggleMenuButton.addEventListener('', function(){
console.log('I am now applied to the element');
});
@skawnkk
Copy link

skawnkk commented Feb 16, 2021

line 32: doucument ->document __typing mistake!
thank you for good article

@disalad
Copy link

disalad commented Nov 9, 2021

thank you so much! i was struggling with that for a while

@adamakers
Copy link

Well explained. Thank you!

@StevenLeonCooper
Copy link

It's worth noting that binding events to individual elements isn't necessarily the best way to do things. Click events are user-initiated so if you have dynamically-generated elements, why not just use the document or body as a delegate for ALL click events and execute different actions based on attributes of the things being clicked? By doing this you can dynamically add or remove elements however you see fit and use whatever method you want to do it and never worry about binding events. This performs perfectly well since there's no real cost to having a single click event bound to the document body when nothing is being clicked on and any HTML page so thick with elements that this would create a noticeable difference would likely have poor performance even when nothing is being clicked on.

@jesperorb
Copy link
Author

It's worth noting that binding events to individual elements isn't necessarily the best way to do things. Click events are user-initiated so if you have dynamically-generated elements, why not just use the document or body as a delegate for ALL click events and execute different actions based on attributes of the things being clicked? By doing this you can dynamically add or remove elements however you see fit and use whatever method you want to do it and never worry about binding events. This performs perfectly well since there's no real cost to having a single click event bound to the document body when nothing is being clicked on and any HTML page so thick with elements that this would create a noticeable difference would likely have poor performance even when nothing is being clicked on.

Yes, that is a valid point and you can definitely do that. Technically it would not matter much for the end result. The only issue I would have with it is maintainability and having a single click as point of entry for everything in our application, I feel personally that the click handler would quickly get messy. Great input :)

@StevenLeonCooper
Copy link

StevenLeonCooper commented Mar 1, 2022

I had the same concern with messy click handlers but I found an elegant way to get around that. The click handler is actually dead simple, it just reads an attribute on the thing you clicked and then tries to invoke a function with that same name as a callback with the event object. You can then organize these functions however you like. Have a clickHandlers object with named properties that match them or just define them right in the JS file. Here's a sample:

HTML:

<div>
  <button type="button" data-action="sayHi">
    Say Hello
  </button>
  <hr>
  <button type="button" data-action="sayMessage" data-message="Howdy!">
    Say Howdy
  </button>
  <hr>
  <input type="text" id="CustomMessage" size="10" placeholder="Type Here">
  <button type="button" data-action="sayCustom" data-for="#CustomMessage">
    Say a Custom Message
  </button>
</div>

JavaScript:

const clickHandlers = {};

clickHandlers.sayHi = () => {
  alert("Hello");
};

clickHandlers.sayMessage = (src) => {
  let msg = src.dataset.message ?? "No Message!";
  alert(msg);
};

clickHandlers.sayCustom = (src) =>{
	let selector = src.dataset.for ?? "body";
  let text = document.querySelector(selector).value;
  alert(text);
};

document.addEventListener("click", (e) => {

  let source = e.target;
  let action = source.dataset.action;
  clickHandlers[action]?.(source, e);
});

That's an over-simplified version but it demonstrates how you can think about the "One Delegate to Rule them All" pattern.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment