It turns out that lots of simple interaction can be added to your app or website with a tiny bit of javascript, and... well a lot of css. But more importantly, the little bit of javascript can be abstracted, and then only css is will be necessary to make new interactions.
Activating things can be seen as the process of adding the class of .active
to an element. What does this do? Nothing, until you use that class with css or javascript.
For the next few examples, I'll break them down into jQuery, qdelegate, and vanilla javascript examples. Understand that this concept will work perfectly fine without delegation, but not if the elements are being created dynamically after page load.
// jQuery
$(document).on("click","[data-activate]",e=>{
$($(e.target).data("activate"))
.addClass("active");
});
// qdelegate
qdelegate("body")("click","[data-activate]",e=>{
document.querySelectorAll(e.target.dataset.activate)
.forEach(o=>o.classList.add("active"));
});
// no delegation, vanilla javascript
document.querySelectorAll("[data-activate]").forEach(o=>{
o.addEventListener("click",e=>{
document.querySelectorAll(e.target.dataset.activate)
.forEach(o=>o.classList.add("active"));
});
});
So what is this? This is something where we use the data- attribute concept of html and javascript to add a selector to an element, so that when one element is clicked, it adds a class of active to some other element. Let's see an example.
<div id="activate-1">Activate this.</div>
<button type="button" data-activate="#activate-1">Click me to activate that</button>
To be perfectly honest, that probably looked like it didn't work. But it did. The javascript worked. In fact, if you were to browser inspect that "activate this" element, you would notice that, after having clicked the button, it was given an .active
class.
Let's add some css to our example to make it change when activated.
<div class="select" id="activate-2">Activate this.</div>
<button type="button" data-activate="#activate-2">Click me to activate that</button>
.select.active {
color:white;
background-color:blue;
}
Did you catch that? It only happens once. So this is the basic premise of everything that comes after this. Adding or removing a class of active to an element. Everything else is some variation of that, and it all revolves around setting up some one time javascript, and then designing everything else with html and css.
But only being able to activate is not very useful. So let's add a deactivate.
// jQuery
$(document).on("click","[data-deactivate]",e=>{
$($(e.target).data("deactivate"))
.removeClass("active");
});
// qdelegate
qdelegate("body")("click","[data-deactivate]",e=>{
document.querySelectorAll(e.target.dataset.deactivate)
.forEach(o=>o.classList.remove("active"));
});
// no delegation, vanilla javascript
document.querySelectorAll("[data-deactivate]").forEach(o=>{
o.addEventListener("click",e=>{
document.querySelectorAll(e.target.dataset.deactivate)
.forEach(o=>o.classList.remove("active"));
});
});
It's the exact same concept. And it's basically got to be duplicated but different. It might be possible to do these all from one concept, but I don't think it's worth your time to explore. They're really small, but they do enough differently.
<div class="select active" id="activate-3">Activate this.</div>
<button type="button" data-activate="#activate-3">Activate that</button>
<button type="button" data-deactivate="#activate-3">De-activate that</button>
So let's take the previous example and add in our new deactivate button. It works in the exact same way. But this example seems tedious, if we have to switch buttons each time we toggle the value, so let's take it to the next step.
// jQuery
$(document).on("click","[data-toggle]",e=>{
$($(e.target).data("toggle"))
.toggleClass("active");
});
// qdelegate
qdelegate("body")("click","[data-toggle]",e=>{
document.querySelectorAll(e.target.dataset.toggle)
.forEach(o=>o.classList.toggle("active"));
});
// no delegation, vanilla javascript
document.querySelectorAll("[data-toggle]").forEach(o=>{
o.addEventListener("click",e=>{
document.querySelectorAll(e.target.dataset.toggle)
.forEach(o=>o.classList.toggle("active"));
});
});
<div class="select" id="activate-4">Toggle this.</div>
<button type="button" data-toggle="#activate-4">Toggle that</button>
Same implementation. You should be getting the idea now.
// jQuery
$(document).on("click","[data-activateone]",e=>{
$($(e.target).data("activateone"))
.addClass("active")
.siblings().removeClass("active");
});
// qdelegate
qdelegate("body")("click","[data-activateone]",e=>{
document.querySelectorAll(e.target.dataset.activateone)
.forEach(o=>Array.from(o.parentElement.children)
.forEach(c=>c.classList[o==c?'add':'remove']("active")));
});
// no delegation, vanilla javascript
document.querySelectorAll("[data-activateone]").forEach(o=>{
o.addEventListener("click",e=>{
document.querySelectorAll(e.target.dataset.activateone)
.forEach(o=>Array.from(o.parentElement.children)
.forEach(c=>c.classList[o==c?'add':'remove']("active")));
});
});
Ok, this one is a little different in its idea, and the code got a bit more complicated without jQuery. jQuery has an easy way to select siblings of an element, and do something to them, but in javascript, we have to go to the parent element, get it's children, and then check the children against whether or not the current one is the original one.
So what even is the point of this one. Well sometimes what you want to do is add active to one element, and turn off active on all of its siblings. This gives us a handy way to activate only one item in a list. Let's see it in action.
<div>
<span class="select" id="activate-5-1">thing</span>
<span class="select" id="activate-5-2">thing</span>
<span class="select" id="activate-5-3">thing</span>
</div>
<div>
<button type="button" data-activateone="#activate-5-1">1</button>
<button type="button" data-activateone="#activate-5-2">2</button>
<button type="button" data-activateone="#activate-5-3">3</button>
</div>
That's it. That's the whole thing. With these four tools, we can make all kinds of interactions. It's possible you can improve these, or add something useful to them. I'd love to hear your ideas, but for now, let's gather them together.
// jQuery
$(document)
.on("click","[data-activate]",e=>$($(e.target).data("activate")).addClass("active"));
.on("click","[data-deactivate]",e=>$($(e.target).data("deactivate")).removeClass("active"));
.on("click","[data-toggle]",e=>$($(e.target).data("toggle")).toggleClass("active"));
.on("click","[data-activateone]",e=>$($(e.target).data("activateone")).addClass("active").siblings().removeClass("active"));
// qdelegate
qdelegate("body")
("click","[data-activate]",e=>{
document.querySelectorAll(e.target.dataset.activate)
.forEach(o=>o.classList.add("active"));
})
("click","[data-deactivate]",e=>{
document.querySelectorAll(e.target.dataset.deactivate)
.forEach(o=>o.classList.remove("active"));
})
("click","[data-toggle]",e=>{
document.querySelectorAll(e.target.dataset.toggle)
.forEach(o=>o.classList.toggle("active"));
})
("click","[data-activateone]",e=>{
document.querySelectorAll(e.target.dataset.activateone)
.forEach(o=>Array.from(o.parentElement.children).forEach(c=>c.classList[o==c?'add':'remove']("active")));
});
// no delegation, vanilla javascript
document.querySelectorAll("[data-activate]").forEach(o=>{
o.addEventListener("click",e=>{
document.querySelectorAll(e.target.dataset.activate)
.forEach(o=>o.classList.add("active"));
});
});
document.querySelectorAll("[data-deactivate]").forEach(o=>{
o.addEventListener("click",e=>{
document.querySelectorAll(e.target.dataset.deactivate)
.forEach(o=>o.classList.remove("active"));
});
});
document.querySelectorAll("[data-toggle]").forEach(o=>{
o.addEventListener("click",e=>{
document.querySelectorAll(e.target.dataset.toggle)
.forEach(o=>o.classList.toggle("active"));
});
});
document.querySelectorAll("[data-activateone]").forEach(o=>{
o.addEventListener("click",e=>{
document.querySelectorAll(e.target.dataset.activateone)
.forEach(o=>Array.from(o.parentElement.children)
.forEach(c=>c.classList[o==c?'add':'remove']("active")));
});
});
Here are some examples that use the data-activate concept here on tutsos.