views:

3064

answers:

3

New to jQuery but quite fascinated with it and really loving it. Starting to turn me off, though, with this problem. Would really appreciate any help. Spent the last week trying to make heads or tails out of it. I apologize if this problem has been posted before.

I have a list of products. Each product is enclosed in a <div>. Inside each div has a floated <span> for product information and an <a> to go the appropriate URL of the product. This list is generated programmatically using ASP.NET.

<div id="prod1">
   <span id="infoProd1" class="prodInfo" />
   <a class="prodURL" href="url1">Name of product #1</a>
</div>
   :
   :

Unfortunately, I don't have a URL as this is only in a development platform behind a firewall. The site pretty much looks like the one below. I hope this helps.

+----------+------------------------------+
|  #prod1  |                              |
+----------+                              |   Each #prodNum div looks like:
|  #prod2  |    overlay and frame divs    |
+----------+       appear over here       |  +-- #prod1 -----------------+
|  #prod3  |     with product details     |  |               |           |
+----------+       only if .prodInfo      |  |  .prodURL     | .prodInfo | 
|          |         is clicked.          |  |               |           |
|    :     |                              |  +---------------------------+
|          |                              |   
+----------+------------------------------+

The information for each product (including photo) is stored in a database.
Depending on the action of the user on the span (i.e. prodInfo), the desired process is:

  • hover will display a small popup with some product info and some details (e.g. price).
  • click will show (animate) a semi-transparent overlay and a <div id="frame"> containing all information regarding the product, including the photo.

I have an image inside the frame that when clicked, would hide the overlay/frame.
Information (including photo) is pulled using jQuery Ajax $.get().
Using jQuery, I was able to achieve this on the first pass (the first click). However, after I close "frame" and hide the overlay, and then hover over any "prodInfo," it'll display the small popup as it should be but at the same time ALSO DISPLAYS the overlay and the "frame" as if I invoked a click.

Here is the simplified jQuery code for the two events:

$(".prodInfo").mouseover(
  function(e) {   // function fired when 'moused over'
    var popupItem = $("#div_infoPopupItem");  // absolute positioned popup
    var prod = $(this).attr('id');
    var prd;

    popupInit(popupItem, e); // changes the top/left coords

    $.ajax({      
      type    : 'GET',
      url     : 'prodInfo.aspx',
      data    : 'id=' + prod,
      success :

        function(prodInfo, status) {
          var prodStr = '<b>No product name.</b>';

          prd = prodInfo.split('::');  // product info delimited by '::'
          prodStr = '<div class="popupInfo_head">' + prd[0] + '</div>' +
                    '<div style="margin:2px;">' + prd[1] + '</div>';
                    // and so on...

          popupItem.html(prodStr);
          return false;
        },
    error :
      function() {
        popupItem.html('Error in collecting information.');
      }
    });

    popupItem.animate({ opacity : .94 }, { queue:false, duration: 120 });
    return false;
  }
);

$(".prodInfo").click(
  function(e) {
    var prod    = $(this).attr('id');
    var frame   = $("#div_frame");
    var overlay = $("#div_overlay");
    var info;
    var img     = new Image();

    document.getElementById('div_frame').scrollTop = 0;
    $.get('prodInfo.aspx', { id: prod },
      function (result) {
        info = result.split(';;');     // name ;; status ;; description ;; price, etc.

        $(this).ajaxSuccess(
          function (e, request, settings) {
            img.src = 'prodImage.aspx?id=' + prod;
            img.id  = 'prodImg';

            //populate the frame with prod info
            $(img).load(function () {
              $("#prodInfoImage")
                  .css('background', 'transparent url("prodImage.aspx?id=' + prod + '") no-repeat 50% 50%');
              switch (info[1]) {
                case '0':
                    $("#prodStatus")
                        .removeAttr("class")
                        .addClass("status_notavail")
                        .text('Not available');
                        break;
                case '1':
                    $("#prodStatus")
                        .removeAttr("class")
                        .addClass("status_avail")
                        .text('Available');
                        break;
              } // switch

              $("#prodInfoDesc")
                  .empty()
                  .append(info[2]);
              $("#prodInfoExtra")
                  .empty()
                  .append(info[3]);

              $("#prodName").text(info[0]);
            }
          )
          .error(
            function() {
              return false;
            }
          );  // image load

          // animate overlay, frame and display product info
          overlay .animate({ top   : '0' }, { queue: false, duration: 280 })
                  .animate({ height: '100%' }, 280, '',
                    function() {
                      frame.animate({ opacity : .92 }, 320);
                      return false;
                    }
                  );
          return false;
          }
        );     // ajax success
      }
    );  // get
  }
);

Below is the event definition of the "close" image located inside the frame.

$("#img_close").click(
  function (e) {
    $("#div_frame")
      .animate({ opacity: 0}, 100, '', 
        function() {
          $("#div_overlay")
            .animate({ top   : "50%" }, { queue: false, duration: 120 })
            .animate({ height: "0px" }, 120);
        }
      );

      return false;
  }
);

As mentioned, this will work as planned only before the first click. After I click on a prodInfo span and close the frame/overlay, the next mouseover on a prodInfo actually invokes BOTH mouseover and ALSO a click (which shows back the overlay/frame).

EDIT: Thanks to all who responded. I will try to debug it using each of your suggestions.

EDIT(2): Mahalo for everyone who commented and responded.

A: 

I'm going to take a punt, and say that the problem is that you generate/show the popup on the first mouseover/click, and then just render it opaque. On the second mouseover, it looks like the old div is being nabbed and made visible again.

Other than that, if you could provide a URL linking to the page where you have this problem, I can take a deeper look.

Don Werve
Hi DonThanks for your answer. Unfortunately, this is on a dev platform behind the company firewall. I don't have a way to have it on a public-facing URL. I see what you mean by just rendering it opaque but why does it do that? It should only do it on the click and not during a mouseover. Thx
+1  A: 

I can't quite picture the entire setup you have, but this was the first thing that popped to mind. It might be a case of event bubbling, carrying the click event to both the close button and the span. Perhaps when you click the close event, the span click might also fire, but the frame is being hidden by the close event. Check out the bind function for more info on stopping default action and event bubbling: http://jquery.bassistance.de/api-browser/#bindStringObjectFunction

As Don mentioned, a sample URL would definitely help a lot!

Edit:

Upon further examination, I think that it's the way you're attaching the ajaxSuccess event within the click() event. It might still be active and firing whenever ANY ajax request is made.

Edit, again:

I've just confirmed this with my own test of the code and it definitely seems to be the issue. In fact, it's attaching the ajaxSuccess function each time you click, so if you've clicked five times, it executes that function five times. Since an AJAX request is made in the mouseover event, it's also firing the previously attached ajaxSuccess functions and showing your overlay and frame.

To get around this try the following:

Instead of:

    $.get('prodInfo.aspx', { id: prod },
  function (result) {
    info = result.split(';;');     // name ;; status ;; description ;; price, etc.

    $(this).ajaxSuccess(

Try:

    $.get('prodInfo.aspx', { id: prod },
  function (result, statusText) {
    info = result.split(';;');     // name ;; status ;; description ;; price, etc.

    if ( statusText == 'success' ) {
PHPexperts.ca
thanks for testing it out yourself.so just wrap the ajaxSucess within the if condition where statusText is a global var? and within the ajaxSuccess callback, set statusText to 'success' on the last line? i did suspect the culprit being either the ajax or the image load. i will try it out. thanks
Actually, you will have to drop the ajaxSuccess bit alltogether. The 'statusText' variable is provided by jQuery automatically (I've named it statusText, but the second variable of the .get callback function is the status of the request.) Hope that makes sense, let me know if not!
PHPexperts.ca
thanks, PHPexpertsI'll try your suggestion.
PHPexperts I can't thank you enough. I was ready to lose my mind trying to figure out what was wrong. Aloha and Mahalo.
A: 

the problem might be that you aren't hiding what was created on the click when you do the mouseover. So, when you mouseover again, you are showing the first, but since the first now has the click event item in it, it shows it as well. You'll want to hide the click event item on mouseover, so it doesn't show as well.

Jeremy B.