views:

559

answers:

3

Hi guys

need your help on hover mouse out event not firing

Problem

i basically have simple link list and when you hover over it it appends a div (loading data in this div from xml) and on hover out it removes the div, but it only happens when mouse moves slowly over the links as soon as mouse moves more fast then usual over the links then it doesnt remove the div which means mouseout event was not fired

move your mouse aggressively on first 2 links then you can see that div some times doesnt hide

here is link to my demo http://ukcatonline.com/template/

also i am copying my js code here

$(document).ready(function () { 

//vertical navigation js
$(".mainnav_v a").hover(
 function (e) {
  $this = $(this)
  $this.stop().animate({ paddingLeft : '16px'}, 300);

  var brand ="";
  var category="designer_frames";
  $this.each(function() 
  {
   var title = this.title;
   if ($this.is('a') && $this.attr('title') != '' && $this.attr('id')==category)
   {  
    brand= this.title;

    $.ajax({
     type: "GET",
     url: "xml/peek_menu.xml",
     //ie bug : it send wrong datatype on localmachine
     dataType: ($.browser.msie) ? "text" : "xml",
     success: function(data) {
      var xml;
       if (typeof data == "string") {
         xml = new ActiveXObject("Microsoft.XMLDOM");
         xml.async = false;
         xml.loadXML(data);
       } else {
         xml = data;
       }
      //could have used $(xml).find(category).each(function() but jquery is intelligent enough to know wat element is currently selected
      $(category, xml).each(
       function(){
        $(brand,this).each(
         function(){
          var title = $(this).attr('title');
          var imgurl = $(this).attr('imgurl');
          var description = $(this).find('description').text();
          var feature1 = $(this).find('feature1').text();
          var feature2 = $(this).find('feature2').text();
          var feature3 = $(this).find('feature3').text();
          var feature4 = $(this).find('feature4').text();

          var html =  '<div id="peek_container"><img src="' + imgurl + '" alt="" /><br /><br /><h1>'+title+'</h1><br />';
          html += '<p>' + description + '</p><br />';
          html += '<ul><li>'+feature1+'</li><li>'+feature2+'</li><li>'+feature3+'</li><li>'+feature4+'</li></ul><br /></div>';
          $this.parent().append(html);
         }
        );
       }
      );
     }
    }
    );

   }
  });

 },
 function (e) {
  $this = $(this);
  $this.stop().animate({ paddingLeft : '6px' }, 300);
  $this.siblings().remove();
 }
);});

and html

<ul class="mainnav_v">
  <li><a href="#url" class="peek" title="Boss" id="designer_frames">Boss</a></li>
  <li><a href="#url" title="Burberry" id="designer_frames">Burberry</a></li>
  <li><a href="#url" title="Bvlgari" id="designer_frames">Bvlgari</a></li>
  <li><a href="#url">Chanel</a></li>
  <li><a href="#url">Diesel</a></li>
  <li><a href="#url">Dior</a></li>

waiting for help

salman

+1  A: 

I am not 100% sure but my gut feeling is, the function call to get the panel via ajax should be a callback of the hover animate function.

The way it is now, the hover animate is 'independent' of the ajax call.

I've not tried this so I might be wrong. :P

o.k.w
thanks man, this worked like charm, why i didnt think of this, silly me, buy your self a drink and pretend its from me :)gud man the laltianRegardssalman
Salman
Ermm.. ok... I go buy one now. Anyway, just glad my 'gut feeling' helps :P
o.k.w
A: 

Using console.log() or some other logging method you should be able to determine if the mouseout is firing before the mouseover is finished adding content, or if there is another problem.

Jason Aller
yeah jason did that and found out that it wasnt firing and then o.k.w kindly suggested that i should use a callback function in animation function i tried that and it worked
Salman
+1  A: 

Let us examine an offending order of operations:

  • Mouse over - Start Ajax Call
  • Mouse out - remove siblings
  • ajax success - append div.

Add in the fact that you aren't using var $this to declare $this - therefore it is global, the $this in the ajax call could be getting overwritten.

You should probably change your function to create and append the <div> before the ajax call, and then append to it later (added comments):

$(document).ready(function () { 
  //vertical navigation js
  $(".mainnav_v a").hover(function (e) {
    // be sure to SCOPE your $this, so that the other function can't overwrite it
    var $this = $(this)
    $this.stop().animate({  paddingLeft : '16px'}, 300);
    var brand ="";
    var category="designer_frames";
    $this.each(function() {
      var title = this.title;
      if ($this.is('a') && $this.attr('title') != '' && $this.attr('id')==category)
      {  
        brand= this.title;
        // create div BEFORE ajax call, and append it to dom in a hidden state
        var $results = $("<div id='peek_container'/>").hide();
        $this.parent().append($results);
        $.ajax({
          type: "GET",
          url: "xml/peek_menu.xml",
          //ie bug : it send wrong datatype on localmachine
          dataType: ($.browser.msie) ? "text" : "xml",
          success: function(data) {
            var xml;
            if (typeof data == "string") {
              xml = new ActiveXObject("Microsoft.XMLDOM");
              xml.async = false;
              xml.loadXML(data);
            } else {
              xml = data;
            }
            $(category, xml).each(function(){
              $(brand,this).each(function(){
                var title = $(this).attr('title');
                var imgurl = $(this).attr('imgurl');
                var description = $(this).find('description').text();
                var feature1 = $(this).find('feature1').text();
                var feature2 = $(this).find('feature2').text();
                var feature3 = $(this).find('feature3').text();
                var feature4 = $(this).find('feature4').text();

                var html =  '<img src="' + imgurl + '" alt="" /><br /><br /><h1>'+title+'</h1><br />';
                html += '<p>' + description + '</p><br />';
                html += '<ul><li>'+feature1+'</li><li>'+feature2+'</li><li>'+feature3+'</li><li>'+feature4+'</li></ul><br />';
                // set the html of the results object we made.
                $results.show().html(html);
              });
            });
          }
        });
      }
    });
  },
  function (e) {
    var $this = $(this);
    $this.stop().animate({  paddingLeft : '6px'     }, 300);
    $this.siblings().remove();
  });
});
gnarf
i can see your idea working as well, but problem is solved from o.k.w's suggestion of using callback function, but i can see your idea working as well, but for now i am happy with callback (short on time) thanks for answering will implement it later
Salman
All using the callback has done is make your problem even more dependent on timing... Now you will experience the same problem (and probably more) if you move the mouse off the element, onto the other one between the ajax call beginning and finishing...
gnarf
@gnarf: I can see the value in your method. +1 for that.Here's my view on using callback to trigger ajax call. The animate sequence was 'stopped' upon mouseout hence the ajax call will not be triggered before the animation completes. The original case always make the ajax call regardless of animation completion, which I consider undesirable. So I don't think it can be a worse solution than the original one. :)
o.k.w
@o.k.w. - but the problem still exists, just 300ms later in the call chain. Imagine you mouseover, animation finishes, ajax starts, mouseout (doesn't remove div, because ajax call hasn't completed), then ajax completes adding div (and since we aren't scoping $this, it will add to whatever $this set to, maybe the new mouseover element, maybe the old one...) all sorts of wrong behavior there... I think solving the problem at the core instead of delaying them by 300ms is more desireable.
gnarf
you are rite and thats why i said i will implement this one along with o.k.w 's solution but at the moment callback is fine because i know ajax call wont be long enough to cause any problem but for future use its worth implementing your solution, i totally agree
Salman
Well gentlemen, all's good I guess. A quickfix first, then a fix-it-all implementation. :)
o.k.w

related questions