RGBK
RGBK

Reputation: 2048

jQuery — trigger a live event only once per element on the page?

Here's the scenario

$("p").live('customEvent', function (event, chkSomething){ 
//this particular custom event works with live
    if(chkSomething){
        doStuff();
        // BUT only per element
        // So almost like a .one(), but on an elemental basis, and .live()?
    }
})

Here's some background

The custom event is from a plugin called inview

The actual issue is here http://syndex.me

  1. In a nutshell, new tumblr posts are being infnitely scrolled via javascript hack (the only one out there for tumblr fyi.)
  2. The inview plugin listens for new posts to come into the viewport, if the top of an image is shown, it makes it visible.
  3. It's kinda working, but if you check your console at http://.syndex.me check how often the event is being fired
  4. Maybe i'm also being to fussy and this is ok? Please let me know your professional opinion. but ideally i'd like it to stop doing something i dont need anymore.

Some things I've tried that did not work:

  1. stopPropagation

  2. .die();

  3. Some solutions via S.O. didnt work either eg In jQuery, is there any way to only bind a click once? or Using .one() with .live() jQuery

I'm pretty surprised as to why such an option isnt out there yet. Surely the .one() event is also needed for future elements too? #justsayin

Thanks.

Upvotes: 1

Views: 2153

Answers (3)

Kevin B
Kevin B

Reputation: 95018

Add a class to the element when the event happens, and only have the event happen on elements that don't have that class.

$("p:not(.nolive)").live(event,function(){
  $(this).addClass("nolive");
  dostuff();
});

Edit: Example from comments:

$("p").live(event,function(){
  var $this = $(this);
  if ($this.data("live")) {
    return;
  }
  $this.data("live",true);
  doStuff();
});

Upvotes: 2

voithos
voithos

Reputation: 70562

Like Kevin mentioned, you can accomplish this by manipulating the CSS selectors, but you actually don't have to use :not(). Here's an alternative method:

// Use an attribute selector like so. This will only select elements
// that have 'theImage' as their ONLY class. Adding another class to them
// will effectively disable the repeating calls from live()
$('div[class=theImage]').live('inview',function(event, visible, visiblePartX, visiblePartY) {
   if (visiblePartY=="top") {
      $(this).animate({ opacity: 1 });
      $(this).addClass('nolive');
      console.log("look just how many times this is firing")
   }
});

I used the actual code from your site. Hope that was okay.

Upvotes: 1

Kato
Kato

Reputation: 40582

This one works (see fiddle):

jQuery(function($) {
    $("p").live('customEvent', function(event, chkSomething) {
        //this particular custom event works with live
        if (chkSomething) {
            doStuff();
            // BUT only per element
            // So almost like a .one(), but on an elemental basis, and .live()?
            $(this).bind('customEvent', false);
        }
    });

    function doStuff() {
        window.alert('ran dostuff');
    };

    $('#content').append('<p>Here is a test</p>');

    $('p').trigger('customEvent', {one: true});
    $('p').trigger('customEvent', {one: true});
    $('p').trigger('customEvent', {one: true});
});

This should also work for your needs, although it's not as pretty :)

$("p").live('customEvent', function (event, chkSomething){ 
    //this particular custom event works with live
    if(chkSomething && $(this).data('customEventRanAlready') != 1){
        doStuff();
        // BUT only per element
        // So almost like a .one(), but on an elemental basis, and .live()?
        $(this).data('customEventRanAlready', 1);
    }
})

Upvotes: 1

Related Questions