views:

326

answers:

1

I have two types of links that are event-bound. If the clicked-on link has the class 'flagged', the event handler calls recallFlag, else doFlag function.

$(document).ready(function()  {

$('div.flag-link, span.flag-link').bind('click', function(e){
 if ($(e.target).attr('class')=='flagged') doRecall(e);
 else doFlag(e);
 return false;
});

The doFlag function loads a form, and when the user submits it, receives json data. Using that data, it changes the link's href and class (flagged-->unflagged and vice-versa).

When the user flags an item for a first time, the execution is ok. But when for a second time the user clicks on a different link to flag another item, I have a weird behavior: event.target is changed to the first element (that was clicked at the first time) inside the callback function of the post event. As a result, a wrong link (the link that was clicked previously) is updated.

What am I doing wrong?

function doFlag(e) {

    var link = e.target;
    var $prnt = $(link).parent();
    var $url = $(link).attr('href');
    console.log('new attempt to flag:' + $(link).attr('href'));

    Boxy.load($url, {modal:true, title:e.target.innerHTML, closeText:'[Kapat]', unloadOnHide:true, cache:false, behaviours: function(r) {

 $("#flag-form-submit").live("click", function(){
  var post_url = $("#flag-form").attr('action'); 
  $.post(post_url, $("#flag-form").serialize(), function(data){

    //THIS IS WHERE THE CODE SCREWS UP:
    //here "link" is changed to the former link that triggered the event previously    
    if (data.status == 'ok') {

     $(link).attr('href', data.url);
     $(link).attr('class', data.css_class);
     $(link).attr('innerHTML', data.text);
     $prnt.children('img.flag-img').css('visibility', 'visible');

    }


   }, "json");
  boxy = Boxy.get(this);
  boxy.hideAndUnload();      
  return false;
 });
 }
});
+1  A: 

It is because you are using a .live event. Basically you should only be binding this once per page session however you are adding a live event to the stack each time but your only seeing the first one added after you click the first link.

For the least amount of code change instead of the .live you could use a click but making sure you unbind it first

e.g

$("#flag-form-submit").unbind('click').click( function(){
    var post_url = $("#flag-form").attr('action');
    .....

});

If you want to refactor large parts of it then I would move the live handler outside of that function, bind it in doc ready and then store the current link using .data on the #flag-form-submit element.

$("#flag-form-submit").data('currentLink', link);

then inside the live event

if (data.status == 'ok') {

       var $link = $("#flag-form-submit").data('currentLink');
       $link.attr('href', data.url);
       $link.attr('class', data.css_class);
       $link.attr('innerHTML', data.text);
       $prnt.children('img.flag-img').css('visibility', 'visible');

}
redsquare
You have been very helpful. Following your guidance, I added $(this).die('click'); to the end of the click event function. It also seems to work flawlessly. Is it ok to go on with it or should I use one of your solutions?
shanyu
better to use the click or event just .one(fn) . There is no benefit using live as you change the implementation each time.
redsquare
I initially used click, but I switched to live because using click didn't bind the element to the event. I suspected it was due to the form's elements were not loaded fully at the time the event binding code was executing. Therefore I switched to live and it worked. Shortly, I am not sure how I can use click :)
shanyu
if you load that button in using ajax (not sure how boxy works) then yeah live will be the way forward as the button needs to be in the dom when using .click
redsquare
boxy loads it via ajax, so it seems I have to stick with live. Thanks a lot for the help.
shanyu
no worries, good luck with it:)
redsquare