Event delegation (without jQuery)
Event delegation is a pattern where a container element has a single event listener that handles events for all descendants that match a CSS selector.
This pattern was popularized by jQuery that lets you do this:
$('.container').on('click', '.message', function(event) {
console.log("A message element was clicked!")
})
This technique has some advantages:
- When you have many descendants, you save time by only registering a single listener.
- When the descendants are changed dynamic...
JavaScript without jQuery
This is a presentation from 2019-01-21.
Summary
- We want to move away from jQuery in future projects
- Motivations are performance, bundle size and general trends for the web platform.
- The native DOM API is much nicer than it used to be, and we can polyfill the missing pieces
- Unpoly 0.60.0 works with or without jQuery
Is jQuery slow?
From: Sven
To: unpoly@googlegroups.com
Subject: performance on smartphones and tablets
Hello
I just used your framework in one project and must say,
I am really pleased with it -- but o...
Events triggered by jQuery cannot be observed by native event listeners
jQuery has a function $.fn.trigger()
. You can use it to dispatch an event on a jQuery object:
let $element = $('.foo')
$element.trigger('change')
A caveat is that such an event will be received by jQuery event listeners, but not by native event listeners:
let $element = $('.foo')
$element.on('change', event => console.log('I will be called'))
$element[0].addEventListener('change', event => console.log("I WON'T be called"))
$element.trigger('change')
This is not an issue when your entire app is ...
Webpack: How to avoid multiple versions of jQuery
To avoid multiple versions of a package, you can manually maintain a resolutions
section in your package.json
. We recommend you to do this for packages like jQuery. Otherwise the jQuery library attached to window
might not include the functions of your packages that depend on jQuery.
Note: This is only an issue in case you want to use a package functionality from window
e.g. $(...).datepicker()
from your dev console or any other javascript within the application.
Background
By default yarn will create a folder node_modules
...
How to create memory leaks in jQuery
jQuery doesn't store information about event listeners and data
values with the element itself. This information is instead stored in a global, internal jQuery cache object. Every time you add an event listener or data value to a jQuery object, the jQuery cache gains another entry.
The only way that a jQuery cache entry gets deleted is when you call remove()
on the element that put it there!
Since cache entries also have a pointer back to the element that spawned them, it is easy to create DOM elements that can never be garbage-co...
Select2 alternatives without jQuery
Select2 is a fantastic library for advanced dropdown boxes, but it depends on jQuery.
Alternatives
Tom Select
There is a selectize.js
fork called Tom Select. It is well tested, comes with Bootstrap 3, Bootstrap 4 and Bootstrap 5 styles and is easy to use. You might miss some advanced features.
Known issues:
- Dynamic opt-groups in AJAX requests are not supported, you need to define them in advance on the select field (see <https://github.com/selectize/selectize.js/pull/1226/...
jQuery and cross domain AJAX requests
When making cross-domain AJAX requests with jQuery (using CORS or xdomain or similar), you will run into issues with HTTP headers:
- jQuery will not set the
X-Requested-With
header. On your server, requests will not look like AJAX requests (request.xhr?
will befalse
). - jquery-ujs will not set CSRF headers.
This is by design and improves secu...
jQuery: Work with text nodes and comment nodes
Nearly all jQuery traversal functions ignore elements that are not HTML tags.
To work with other type of nodes (like text, comment or CDATA sections) you need to:
- Retrieve child nodes
contents()
(which behaves likechildren()
except that it returns all types of child nodes) - Filter manually using either plain Javascript or jQuery's
filter()
method
Example
Let's write a function that takes a jQuery element and returns an array of all child nodes that are text nodes:
function selectTextNodes($container) {
retu...
How to show jQuery event handler on element
Chrome gives you the currently selected element in the inspector with $0
. If you select a button in the DOM you can set and inspect the event handler with the following two code lines:
$($0).on('click', function() { console.log('Hello') })
jQuery._data($0, "events").click[0].handler
// => "function () { console.log('Hello') }"
This is useful for debugging.
jquery-timing - a jQuery plugin you should know about
jquery-timing is a very useful jquery plugin that helps to remove lots of nested anonymous functions. It's API provides you some methods that help you to write readable and understandable method chains. See yourself:
Example
// before
$('.some').show().children().doThat();
window.setTimeout(function(){
$('some').children().doSomething().hide(function() {
window.setTimeout(function() {
otherStuffToDo();
}, 1000);
});
}, 500);
// after
$('.some').s...
Guideline for moving from jQuery to vanilla JavaScript
jQuery is still a useful and pragmatic library, but chances are increasingly that you’re not dependent on using it in your projects to accomplish basic tasks like selecting elements, styling them, animating them, and fetching data—things that jQuery was great at. With broad browser support of ES6 (over 96% at the time of writing), now is probably a good time to move away from jQuery.
[Practical and clear reference with the most common jQuery patterns and their equivalent translations in vanilla JS](https://tobiasahlin.com/blog/move-from-j...
Traversing the DOM tree with jQuery
jQuery offers many different methods to move a selection through the DOM tree. These are the most important:
$element.find(selector)
Get the descendants of each element in the current set of matched elements, filtered by a selector. Does not find the current element, even it matches. If you wanted to do that, you need to write $element.find(selector).addBack(selector)
.
$element.closest(selector)
Get the first ancestor el...
jQuery promises: done() and then() are not the same
jQuery's deferred objects behave somewhat like standard promises, but not really.
One of many subtle differences is that there are two ways to chain callbacks to an async functions.
The first one is done
, which only exists in jQuery:
$.ajax('/foo').done(function(html) {
console.debug("The server responded with %s", html);
});
There is also then
, which all promise libraries have:
$.ajax('/foo').then(function(html) {
console.debug("The server resp...
Manually trigger a delegated DOM event
When you register a delegated event using on
(or the deprecated delegate
/ live
), it is somewhat hard to manually trigger these events manually, e.g. for testing.
After trying jQuery's trigger
to no avail, I had success by using native Javascript methods to create and dispatch an event. For instance, to trigger a mousedown
event:
element = $('...').get(0);
event = new MouseEvent('mousedown', { view: window, cancelable: true, bubbles: true }...
Unobtrusive JavaScript and AJAX
Attached (see below) is some code to allow using unobtrusive JavaScript on pages fetched with an AJAX call.
After you included it, you now do not use the usual
$(function() {
$('.some_tag').activateStuff();
});
any more, but instead you write
$.unobtrusive(function() {
$(this).find('.some_tag').activateStuff();
});
that is
-
$.unobtrusive()
instead of$()
- don't do stuff to the whole page, but just to elements nested below
$(this)
Normal pages work as before (your $.unobtrusive
functions are ca...
jQuery.cssHooks – jQuery API
The $.cssHooks object provides a way to define functions for getting and setting particular CSS values. It can also be used to create new cssHooks for normalizing CSS3 features such as box shadows and gradients.
For example, some versions of Webkit-based browsers require -webkit-border-radius to set the border-radius on an element, while earlier Firefox versions require -moz-border-radius. A css hook can normalize these vendor-prefixed properties to let .css() accept a single, standard property name (border-radius, or with DOM property synt...
Trigger a link's click action with Javascript
Use the click
method on the DOM element:
let link = document.querySelector('a')
link.click()
Dynamically uploading files to Rails with jQuery File Upload
Say we want …
- to create a
Gallery
that has a name andhas_many :images
, which in turn have a caption - to offer the user a single form to create a gallery with any number of images
- immediate uploads with a progress bar per image
- a snappy UI
Enter jQuery File Upload. It's a mature library that can do the job frontend-wise. On the server, we'll use Carrierwave, because it's capable of caching images.
(FYI, [here's how to do the u...
A jQuery plugin pattern every jQuery plugin should use
Many jQuery plugins suffer from a good plugin architecture. When you write jQuery plugins you should use the plugin pattern described in this article which makes your plugin highly customizable and extensible.
Related article with patterns for namespaced jquery plugins (more detailed)
DOM API for jQuery users
General hints on the DOM
- the root of the DOM is
document
- custom elements inherit from
HTMLElement
. They need a-
(dash) in their name, e.g.<notification-box>
. - event listeners don't have event delegation à la
.on('click', cssSelector, handler)
Comparison
Action | jQuery | DOM API equivalent |
---|---|---|
Find descendant(s) by CSS selector | .find(selector) |
one: `.querySelector(selecto... |
Use jQuery's selector engine on vanilla DOM nodes
There are cases when you need to select DOM elements without jQuery, such as:
- when jQuery is not available
- when your code is is extremely performance-sensitive
- when you want to operate on an entire HTML document (which is hard to represent as a jQuery collection).
To select descendants of a vanilla DOM element (i.e. not a jQuery collection), one option is to use your browser's native querySelector
and [querySelectorAll
](https://developer.mozilla.org/de/docs/We...
jQuery: How to remove classes from elements using a regular expression
jQuery's removeClass
removes the given class string from an element collection. If you want to remove multiple/unknown classes matching a given pattern, you can do that.
For example, consider a DOM node for the following HTML. We'll reference it by $element
below.
<div class="example is-amazing is-wonderful"></div>
Option A: Selecting classes, then removing them
You can iterate over existing classes, and select matching ones. The example below is ES6, on ES5 could write something similar using jQuery.grep
.
let classes ...
Sticky table header with jQuery
When you want the table headers to always stay around (e.g. because that table is huuuge), use the code below.
Style
table.fixed_table_header{
position: fixed;
top: 0;
width: auto;
display: none;
border: none;
margin: 0;
}
Javascript
;(function($) {
$.fn.fixHeader = function() {
return this.each(function() {
var $table = $(this),
$t_fixed;
function init() {
$t_fixed = $table.clone();
$t_fixed.find('tbody').remove().end().addClass('fi...
Announcing the jQuery Mobile Project | jQuery Mobile
The jQuery project is really excited to announce the work that we’ve been doing to bring jQuery to mobile devices. Not only is the core jQuery library being improved to work across all of the major mobile platforms, but we’re also working to release a complete, unified, mobile UI framework.