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:

  1. When you have many descendants, you save time by only registering a single listener.
  2. 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 be false).
  • 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 like children() 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 and has_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.