0

I have a set of nested elements like such.

<div id="master">
    <span id="num-1" class="num"></span>
    <span id="num-2" class="num"></span>
    <span id="num-3" class="num"></span>
    <span id="num-4" class="num"></span>
</div>

And I have the following script

$( document ).ready( function() {
    $( '#master > span.num' ).click( function() {
        q = $( "span[id*=num-']" ).attr( "id" );
        $( '#master' ).html( '&nbsp;' ).load( 'www.someurl.com/?rating=' + q );
    });
});

The load function returns a completely new set of span elements for inside the div. Problem is that I can't seem to figure out how to get this to work past the first time I click one. Since the click is tied to the spans and the spans get replaced, I understand that they no longer have a script tied to them, but I haven't been able to figure out how to get this to re-tie on the fly. I'm super new to jquery and javascript so any help would be appriciated.

All my experiments with using .live() have merely rendered my script useless. Help?

2
  • 1
    Try live (it associates an event handler whenever a matching element appears in the DOM) Commented Mar 18, 2011 at 21:55
  • My attempts are burried in older revisions in my subversion repository. I'll dig one out if there isn't an answer here when I get back. I tried a number of different approaches to using the live() approach and wasn't able to get them to work. I'm sure it was something simple but I couldn't figure it out. Commented Mar 18, 2011 at 21:58

4 Answers 4

3

EDITED: as suggested by Beejamin

$( function() {
    $('#master').click( function(e) { 
    if (e.target.className.indexOf('num') !== -1) {
        var num = e.target.id.split('-')[1]; //this give you # instead of num-#
        $(this).load( 'rating.php/?rating=' + num );
      }  
    });
});

  $(function() {
    $('.num').live('click',function() {
     var num = this.id.split('-')[1]; //this give you # instead of num-#
        $('#master').load( 'rating.php?rating=' + num );
          return false;
    });
});

I suppose you are trying to do a rating system? just for sake my PHP file look like this:

<?php
  if (isset($_GET['rating'])) {
  $rating = (int) $_GET['rating'];
  for ($i = 1; $i < 5; $i++) {
    $a .= "<a id='num-{$i}' class='num".($rating >= $i ? ' rated' : '')."'></a>";
  }
  echo $a;
}
?>
Sign up to request clarification or add additional context in comments.

4 Comments

jQuery's .live() is a shortcut to a document-level event delegation solution like the one I posted. .live() is kind of a brute-force approach, and isn't nearly as efficient as choosing the element to delegate to yourself.
@Beejamin: dear, you point is valid, i have updated my answer accordingly. ;) +1
Don't get me wrong - .live() is great for a lot of things. Your detection of the className and extraction of the ID is much neater too. Touche and +1!
Thanks. I ended up doing a combination of some of these examples. So new to writing javascript that it was REALLY helpful to see a couple of ways this could be done.
2

There's a better way of handling this called 'event delegation' - rather than assigning your click events to each individual span, you can assign the event to the #master div. Because click events 'bubble up' - when you click any element, the click event will be passed up to the #master div. The event itself contains the .target property, which is a reference to the original element that was clicked.

This is much faster (you only have to assign one event, not many), and only needs to be set once.

Your code example becomes:

$( document ).ready( function() {
    $( '#master' ).click( function(e) {
    if (e.target.className == 'num') {//Check if the target that was clicked is one of the elements we want.
        q = $(e.target).attr('id');
        $('#master').html('&nbsp;').load( 'http://www.someurl.com/?rating=' + q );
      }
    });
});

Here's some background on event delegation: http://www.cherny.com/webdev/70/javascript-event-delegation-and-event-hanlders, and more info on event bubbling: http://www.quirksmode.org/js/events_order.html

The only thing you'd have to watch, is that, if you put extra HTML inside your span.num, e.target will point to that element if it's clicked (which is easy enough to account for). If you're only ever going to have text inside the span, you'll be fine with this code.

Comments

0

You can define a function for that and provide recursion

function spanClicked(){
    q = $( "span[id*=num-']" ).attr( "id" );
    $( '#master' ).html( '&nbsp;' ).load( 'www.someurl.com/?rating=' + q );
    $( '#master > span.num' ).click( spanClicked);
}

$( document ).ready( function() {
    $( '#master > span.num' ).click( spanClicked);
});

Comments

0

You can use jQuery .live() to bind events on the fly. You can check the plugin http://docs.jquery.com/Plugins/livequery For more flexibility.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.