开发者

jQuery toggle() with unknown initial state

I have a project that I am working on that uses a little image to mark a record as a favorite on multiple rows in a table. The data gets pulled from a DB and the image is based on whether or not that item is a favorite. One image for a fav开发者_运维知识库orite, a different image if not a favorite. I want the user to be able to toggle the image and make it a favorite or not. Here's my code:

$(function () {
    $('.FavoriteToggle').toggle(
      function () {
        $(this).find("img").attr({src:"../../images/icons/favorite.png"});
        var ListText = $(this).find('.FavoriteToggleIcon').attr("title");
        var ListID = ListText.match(/\d+/);
        $.ajax({
            url: "include/AJAX.inc.php",    
            type: "GET",
            data: "action=favorite&ItemType=0&ItemID=" + ListID,        
            success: function () {}     
        });
      },
      function () {
        $(this).find("img").attr({src:"../../images/icons/favorite_not.png"});
        var ListText = $(this).find('.FavoriteToggleIcon').attr("title");
        var ListID = ListText.match(/\d+/);
        $.ajax({
            url: "include/AJAX.inc.php",    
            type: "GET",
            data: "action=favorite&ItemType=0&ItemID=" + ListID,        
            success: function () {}     
        });
      }
     );
});

Works great if the initial state is not a favorite. But you have to double click to get the image to change if it IS a favorite initially. This causes the AJAX to fire twice and essentially make it a favorite then not a favorite before the image responds. The user thinks he's made it a favorite because the image changed, but in fact, it's not. Help anybody?


Add a class to the favoriteToggle that defines state. Use that to define the css for your icon rather than swapping out the image. Then it gives you away to easily figure out the state of the favoriteToggle.

$(function() {
$('.FavoriteToggle').click(function(){
    var $this = $(this);
    var id = $this.find('.FavoriteToggleIcon').attr("title").match(/\d+/);
    if ($this.hasClass('isFavorite')){
        $this.removeClass('isFavorite');
    } else {
        $this.addClass('isFavorite');
    }
    $.ajax({
        url: "include/AJAX.inc.php",    
        type: "GET",
        data: "action=favorite&ItemType=0&ItemID=" + id,        
        success: function () {}     
    });
})
});

Add to your css:

.FavoriteToggle .icon{
    background: url("../../images/icons/favorite_not.png");
}
.FavoriteToggle.isFavorite .icon{
    background: url("../../images/icons/favorite.png");
}

By doing this you gain having a class that defines the state so you can do more then just change the image with it if you want to, and it makes it so you are defining image paths in your javascript which is always dirty.


dont know if this goes the right direction for you - but i usually use this as a toggle function - and with some additional php i can even adjust it to the one or the other initial state:

<style type="text/css">
<!--
.mybox_edit { 
display: none; 
} 
-->

</style>

<script language="JavaScript" type="text/JavaScript">
<!--

function toggleBox( box_id ) { 
var box_edit = document.getElementById(box_id + "_edit"); 
var box_show = document.getElementById(box_id + "_show"); 

// is it hidden? 
if ( box_show.style.display == 'none' ) { 
box_show.style.display = 'block'; 
box_edit.style.display = 'none'; 
} else { 
box_show.style.display = 'none'; 
box_edit.style.display = 'block'; 
} 
}
//-->
</script>


$(function () {
  // toggle on click
  $('.FavoriteToggle').click ( function() {
    // prevent duplicate AJAX request with a "loading" flag
    if (!this.isLoading) {
      var $img   = $(this).find("img");
      var ListID = $(this).find('.FavoriteToggleIcon').attr("title").match(/\d+/);

      // flag that we are currently loading something
      this.isLoading = true;       

      // determine the action from the current state of the img 
      if ($img.attr("src").indexOf("favorite.png") > -1)
        var actionVerb = "unFavorite";
      else
        var actionVerb = "mkFavorite";

      $.ajax({
        url: "include/AJAX.inc.php",    
        type: "GET",
        data: {action: actionVerb, ItemType: 0, ItemID: ListID },
        success: function($i) {
          return function() { 
            // change image on success only
            if ($i.attr("src").indexOf("favorite.png") > -1) {
              $i.attr("src", "../../images/icons/favorite_not.png";
            else
              $i.attr("src", "../../images/icons/favorite.png";
          };
        }($img),
        error: function(xhr, textStatus, errorThrown) { 
          // make some note of the error
          alert(textStatus);
        }
        complete: function(p) {
          return function(xhr, textStatus) { 
            // set loading flag to false when done
            p.isLoading = false; 
          };
        }(this)
      });
    }
  });
});

Untested, but you should get the idea.

The whole if ($img.attr("src").indexOf("favorite.png") stuff could much more easily be done by adding a favorite CSS class to the <img>. E.g., in the main function:

var actionVerb = $img.is(".favorite") ? "unFavorite" : "mkFavorite";

and, in the success callback:

if ($i.is(".favorite"))
  $i.attr("src", "../../images/icons/favorite_not.png";
else
  $i.attr("src", "../../images/icons/favorite.png";

// now toggle the CSS class
$i.toggleClass("favorite")


Well, here is what I ended up with, a simplified version of PetersenDidit's post above.

$('.FavoriteToggle').click(function() {
    var id = $(this).attr("title").match(/\d+/);
    if ($(this).hasClass('isFavorite')) {
        $(this).removeClass('isFavorite');
    } else {
        $(this).addClass('isFavorite');
    }
    $.ajax({
        url: "include/AJAX.inc.php",
        type: "GET",
        data: "action=favorite&ItemType=0&ItemID=" + id,
        success: function() {
        }
    });
});
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜