Implementing jQuery’s “One” Functionality in MooTools

By  on  

I like the idea behind jQuery's "one" event method. You allow an event function to be triggered once per Element; after its initial run, the function is removed, never to be heard from again (a.k.a until the next page load). I think there are a lot of use cases for "one" so I've ported it to MooTools.

The MooTools JavaScript

/* one-time event occurrence */
Element.implement({
	one: function(ev,fn) {
		if(!this.oneEvents) { this.oneEvents = []; }
		var oneFunc = function(e) {
			if(!this.oneEvents.contains(fn)) {
				this.oneEvents.push(fn);
				fn.run(e);
			}
			return this;
		};
		this.addEvent(ev,oneFunc);
	}
});

The way I complete this is by storing all of the one events in the element's oneEvent property. I wrap the given function in another function that checks to see if the given function has been used yet. If the function hasn't been run, the event triggers it. If the function has been run, the function directs itself to ignore the occurrence.

The Usage

/* usage */
window.addEvent('domready',function() {
	var myFunc = function(e) {
		e.stop();
		alert('triggered!');
	};
	$$('a').each(function(link) {
		link.one('click',myFunc);
	});
});

I chose this example to show that the event will fire only once per element BUT will fire for each element if the same function is passed to multiple event.

Would you use this Element / Event method?

Recent Features

  • By
    Create Namespaced Classes with MooTools

    MooTools has always gotten a bit of grief for not inherently using and standardizing namespaced-based JavaScript classes like the Dojo Toolkit does.  Many developers create their classes as globals which is generally frowned up.  I mostly disagree with that stance, but each to their own.  In any event...

  • By
    5 Awesome New Mozilla Technologies You’ve Never Heard Of

    My trip to Mozilla Summit 2013 was incredible.  I've spent so much time focusing on my project that I had lost sight of all of the great work Mozillians were putting out.  MozSummit provided the perfect reminder of how brilliant my colleagues are and how much...

Incredible Demos

  • By
    MooTools Zebra Tables Plugin

    Tabular data can oftentimes be boring, but it doesn't need to look that way! With a small MooTools class, I can make tabular data extremely easy to read by implementing "zebra" tables -- tables with alternating row background colors. The CSS The above CSS is extremely basic.

  • By
    prefers-color-scheme: CSS Media Query

    One device and app feature I've come to appreciate is the ability to change between light and dark modes. If you've ever done late night coding or reading, you know how amazing a dark theme can be for preventing eye strain and the headaches that result.

Discussion

  1. Really cool idea, and nicely implemented. I’m not sure that I’d use that method name though – ‘one’ could mean anything. Maybe addEventOnce..?

  2. Hey David, I have a different implementation, which I called oneEvent(), that I’d like you to see. kthxbai

  3. You can do with removeEvent(). Simpler, faster & less code.

  4. Do you have the code somewhere Oskar?

  5. something like this?

    Element.implement({
        one:function(ev,fn){
            var oneFunc = function(e){
                fv.run(e,this);
                this.removeEvent(ev,oneFunc);
            }.bind(this);
            this.addEvent(ev,oneFunc);
            return this;
        }
    });
    
  6. should be fn not fv on the fourth line

  7. should also get the .live functionality added to mootools also, I saw it here: http://dev.k1der.net/dev/live-events-pour-moootools/

  8. The implementation Scott shared is exactly what I would expect to do. Simply wrap the event listener to remove the event when it’s fired.

  9. UPDATE: Aaron Newton mentioned that my above implementation would create a memory leak and give problems with “removeEvents”, so I may update my code above. Scott’s solution above is likely the best solution.

  10. Jesus DeLaTorre

    Would you mind sharing with us how this can create a memory leak?

  11. danik

    Thanks. I use both jQuery and Mootools, and sometimes need to “port” some code from one to other. Now it became simpler.

  12. Updating an old post…
    MooTools doesn’t use Native anymore, I had to change Scott’s solution first line to make it work (if you are not using compatibility mode in MooTools).

    [Element, Window, Document].invoke('implement', {
    

    Instead of

    Native.implement([Element, Window, Document, Events], {
    

    Also, Google’s hosted library (1.4.5) seems to be using compatibility mode.

    Feel free to correct me if I’m doing something wrong here.
    Final code :

    [Element, Window, Document, Events].invoke('implement', {
      one : function(type, fn) {
    	return this.addEvent(type, function() {
    	  this.removeEvent(type, arguments.callee);
    	  return fn.apply(this, arguments);
    	});
      }
    });
    

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!