Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
bling dot js

bling.js

Because you want the $ of jQuery without the jQuery.


You may be interested in bling.js if you get tired of the [].slice.call( document.querySelectorAll('.foo'), function(){ … rodeo. It does this:

// forEach over the qSA result, directly.
document.querySelectorAll('input').forEach(el => /* ... */);

// on() rather than addEventListener()
document.body.on('dblclick', evt => /* ... */);

// classic $ + on()
$('p').on('click', el => /* ... */);

It doesn't do anything else. This is not a jQuery equivalent.

Notes:

  • on() works on elements, document, window, and results from querySelector & querySelectorAll.
  • $ is qSA so if you're grabbing a single element you'll have to [0] it.
  • Bling plays well with authoring ES6
  • Resig explored this stuff a while ago: github.com/jeresig/nodelist
  • Bling doesn't work on Android 2.3 or iOS 5.0. Works everywhere else including IE8 (assuming Function.bind)

Nerdy implementation notes:

  • The NodeList prototype usually inherits from Object, so we move it to Array.
  • I'm curious how ES6/7 would let a NodeList be iterable and inherit from EventTarget
  • Setting Node.prototype.on = EventTarget.prototype.addEventListener is awesome. It works in Chrome/FF but not yet in IE/Safari.
  • I haven't set up any off() or trigger() to map to dispatchEvent & removeEventListener. I'm OK with that.
  • I'm using semi-standard for style. I tried standard sans-semicolons, but can't get used to it.
/* bling.js */
window.$ = document.querySelectorAll.bind(document);
Node.prototype.on = window.on = function (name, fn) {
this.addEventListener(name, fn);
}
NodeList.prototype.__proto__ = Array.prototype;
NodeList.prototype.on = NodeList.prototype.addEventListener = function (name, fn) {
this.forEach(function (elem, i) {
elem.on(name, fn);
});
}
@gregpalaci
Copy link

gregpalaci commented Jun 16, 2015

Would be cool to take all the above suggestions, and add animations obviously.. oh wait that would be jQuery 2.x 😀

Nice sugar micro-library as is!

@Dudemullet
Copy link

Dudemullet commented Jun 16, 2015

In case someone is interested, here's how to add very simple even delegation a-la jQuery. IE9+

Node.prototype.on = window.on = function (name, delegate, fn) {
  if(arguments.length !== 3) {
    return this.addEventListener(name, arguments[1]);
  }

  return this.addEventListener(name, function (e) {
    if(e.target.matches(delegate)){
      return fn.apply(e.target, arguments);
    }
  })
}

@junosuarez
Copy link

junosuarez commented Jun 16, 2015

@paulirish standard is neat, semi-standard is neat, but then there's also javascript whatever

@JSila
Copy link

JSila commented Jun 16, 2015

I implemented this behaviour just recently but not quite as elegant as this.
One note: IE8 lacks support for Array.prototype.forEach.

@bjankord
Copy link

bjankord commented Jun 17, 2015

Love this implementation, you should turn it into a full fledged repo, you've got the code/readme/tests 😄

Was getting an "Object doesn't support property or method 'forEach'" in IE10/IE9 so I updated this lineNodeList.prototype.__proto__ = Array.prototype to NodeList.prototype.forEach = Array.prototype.forEach;

@jasonsperske
Copy link

jasonsperske commented Jun 17, 2015

Combine this with promise.js and get "Promise Bling"?

@pankajbisht
Copy link

pankajbisht commented Jun 18, 2015

Paul you are right. If I worked on nodes, lot of time, I have faced this kind of problem. This is the nice solution for [].slice.call(). But querySelector/querySelectorAll have some browser issue so for this have you any solution?

@ebsen
Copy link

ebsen commented Jun 22, 2015

Line 9 is my favorite.

@blaja
Copy link

blaja commented Jun 24, 2015

I want moar! 😃 Great stuff.

Copy link

ghost commented Jun 26, 2015

can be reffered to by its short url: git.io/blingjs

@spiralx
Copy link

spiralx commented Jul 7, 2015

Line 9 should be replaced with the following:

Object.setPrototypeOf(NodeList.prototype, Array.prototype)

which is part of ES6 and currently supported in IE 11, FF and Chrome - for older browsers, this is a quick polyfill:

if (!Object.setPrototypeOf) {
  Object.setPrototypeOf = function(obj, proto) {
    obj.__proto__ = proto;
    return obj; 
  }
}

Also +1 for Node.prototype.on and NodeList.prototype.on returning this, my versions are:

  Node.prototype.on = window.on = function(names, fn) {
    var self = this

    names.split(' ').forEach(function(name) {
      self.addEventListener(name, fn)
    })

    return this
  }

  NodeList.prototype.on = NodeList.prototype.addEventListener = function(names, fn) {
    this.forEach(function(elem) {
      elem.on(names, fn)
    })

    return this
  }

which also allow binding multiple events like jQuery e.g. node.on('change blur', function(ev) { ... } :)

@dciccale
Copy link

dciccale commented Jul 20, 2015

have you tried ki.js? :D https://github.com/dciccale/ki.js

@hjpbarcelos
Copy link

hjpbarcelos commented Aug 19, 2015

Doing this is somewhat a bad practice:

NodeList.prototype.__proto__ = Array.prototype;

NodeList.prototype.on = NodeList.prototype.addEventListener = function (name, fn) {
  this.forEach(function (elem, i) {
    elem.on(name, fn);
  });
}

Don't mess with the native prototypes!

Why don't you try it this way?

window.$ = document.querySelectorAll.bind(document);

Node.prototype.on = window.on = Node.prototype.addEventListener;

NodeList.prototype.on = NodeList.prototype.addEventListener = function (name, fn) {
     Array.prototype.slice.call(this).forEach(function(elem) {
         elem.addEventListener(name, fn, false);
     });
}

@MadLittleMods
Copy link

MadLittleMods commented Aug 20, 2015

What about changing the prototype of HTMLCollection as well so they are easier to iterate over? You can find HTMLCollection's in properties like ParentNode.children

Not sure of the side effects, yet.

HTMLCollection.prototype.__proto__ = Array.prototype;

@stevermeister
Copy link

stevermeister commented Oct 12, 2015

put code in github repo - https://github.com/stevermeister/bling.js/blob/master/bling.js
to make it open & conveninent for contribution

@gugadev
Copy link

gugadev commented Oct 10, 2016

Better $ to querySelector and $$ to querySelectorAll instead of $('.something')[0].on(...).

@crisdosyago
Copy link

crisdosyago commented Nov 17, 2016

Inspired by this to make a version here https://github.com/dosaygo-coder-0/postjs/blob/master/postbling/src/postbling.js

What's new?

  • on applies to EventTargets and Arrays containing them, so you can do this:
$('*').slice(3).on('click', reveal );
$`div`.on( 'touchstart', dragOn ).on( 'touchend', dragOff );
  • NodeList and HTMLCollection both now delegate to Array
  • the on functions return this to allow chaining
  • and made it more ES5/6/7-y including Object.setPrototypeOf

These included ideas from @MadLittleMods and @spiralx and @joa

@skylarmb
Copy link

skylarmb commented Mar 1, 2017

@bjankord awesome. thanks for the tip. Sadly some of us do have to support IE9... 🎉

@GaurangTandon
Copy link

GaurangTandon commented Mar 17, 2017

This does NOT work for DOM elements inside iframes. Here's the related SO question with a related code sample - based on the same principles as above code - with a reproducible example - http://stackoverflow.com/questions/42825990/extending-prototype-of-dom-elements-inside-iframes
Any ideas anyone?

@Ollie-w
Copy link

Ollie-w commented Jun 5, 2017

Is this safe to use in production?

@paulirish
Copy link
Author

paulirish commented Dec 2, 2017

@Ollie-w yeah totally.

@argyleink
Copy link

argyleink commented Apr 1, 2018

I think I have an interesting fork:

  • only mutates the nodes queried with the exported function
  • offers 'off'
  • offers nice attribute CRUD operations

https://github.com/argyleink/blingblingjs

@paulirish
Copy link
Author

paulirish commented Apr 23, 2020

@AdaRoseCannon has a nice extension of this idea which maps ALL things in the Element prototype onto the NodeList prototype https://gist.github.com/AdaRoseCannon/d95a7cbb8edd730443c62f0daff875ac

@nuxodin
Copy link

nuxodin commented Nov 16, 2020

Similiar:
https://github.com/nuxodin/domProxy
A (proxied) Nodelist with all Apis of Elements (also future).

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