0

I have a dynamic menu populated from MySql database. When one of the items on this menu is clicked, an Ajax request is made and accordingly the tree structure (product categories with their respective subcategories) is highlighted based on the id passed to the Ajax request.

The menu is simply maintained using <ul><li></li></ul> and when mouse button is hovered over one of the items on the menu, some jQuery functions are called to pop up (drop down) the child items. It goes well.

The same type of menus are required to display on the same page for some reasons (only one of those menus uses Ajax. The rest are not required to use Ajax).

The problem is that I have to load jQuery functions to pop up the menu items separately. Once on page load and again on Ajax request. Otherwise, it doesn't pop up the menu. Consequently, it seems to me that two JavaScripts are activated on the browser and they prevent the rest of the menus on the same page from being displayed properly.

It should be noted that when mouse button is hovered. all the menus are shown properly, if Ajax request is not made (via the only menu that uses the Ajax call as mentioned above).

I hope you will be able to understand what I mean. Sorry to say that I can't make my question more defined than this. Why does this happen? Is there a solution to this.

EDIT:

I have this jQuery code used to pop up the menu.

var arrowimages_new={down:['downarrowclass', 'category_parent_css_js/images/down.gif', 3], right:['rightarrowclass', 'category_parent_css_js/images/right.gif']}

var jqueryslidemenu_new={

    animateduration: {over: 200, out: 100}, //duration of slide in/ out animation, in milliseconds

    buildmenu_new:function(menuid, arrowsvar){
        jQuery(document).ready(function($){
            var $mainmenu=$("#"+menuid+">ul")
            var $headers=$mainmenu.find("ul").parent()
            $headers.each(function(i){
                var $curobj=$(this)
                var $subul=$(this).find('ul:eq(0)')
                this._dimensions={w:this.offsetWidth, h:this.offsetHeight, subulw:$subul.outerWidth(), subulh:$subul.outerHeight()}
                this.istopheader=$curobj.parents("ul").length==1? true : false
                $subul.css({top:this.istopheader? this._dimensions.h+"px" : 0})
                $curobj.children("a:eq(0)").css(this.istopheader? {paddingRight: arrowsvar.down[2]} : {}).append(
                    '<img src="'+ (this.istopheader? arrowsvar.down[1] : arrowsvar.right[1])
                    +'" class="' + (this.istopheader? arrowsvar.down[0] : arrowsvar.right[0])
                    + '" style="border:0;" />'
                )

                $curobj.hover(
                    function(e){
                        var $targetul=$(this).children("ul:eq(0)")
                        this._offsets={left:$(this).offset().left, top:$(this).offset().top}
                        var menuleft=this.istopheader? 0 : this._dimensions.w
                        menuleft=(this._offsets.left+menuleft+this._dimensions.subulw>$(window).width())? (this.istopheader? -this._dimensions.subulw+this._dimensions.w : -this._dimensions.w) : menuleft
                        if ($targetul.queue().length<=1) //if 1 or less queued animations
                            $targetul.css({left:menuleft+"px", width:this._dimensions.subulw+'px'}).slideDown(jqueryslidemenu.animateduration.over)
                    },
                    function(e){
                        var $targetul=$(this).children("ul:eq(0)")
                        $targetul.slideUp(jqueryslidemenu.animateduration.out)
                    }
                ) //end hover
            }) //end $headers.each()
            $mainmenu.find("ul").css({display:'none', visibility:'visible', zIndex:'99999'})
            $mainmenu.find("ul li").css({zIndex:'99999'})
        }) //end document.ready
    }
}

The same jQuery is already imported using the src attribute of the <script></script> tag that is used when the page is loaded.

and this is the function that uses the Ajax call.

function getParentId(parentId)
{
    $.ajax({
        datatype:"html",
        type: "GET",
        url: "ajax/ParentId.php",
        data: "ed_id=" + parentId+"&t="+new Date().getTime(),
        success: function(response)
        {       
            $('#originalMenu').html(response);
            jqueryslidemenu_new.buildmenu_new("myslidemenu", arrowimages_new); 
            // The above function is called from here.              
        },
        error: function(e)
        {
            alert('Error: ' + e);
        }
    });
    document.getElementById("txt_parent").value=parentId;   
}


EDIT:

The following is the full HTML code including js (just for the sake of demonstration).

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Test Menu</title>
<link rel="stylesheet" type="text/css" href="category_parent_css_js/cat_parent.css" />
<script src="js/jquery-1.6.min.js" type="text/javascript"></script>
<script type="text/javascript" language="javascript" src="category_parent_css_js/cat_parent_js.js"></script>
<script type="text/javascript" language="javascript">

    //This code is used to pop up menu after an Ajax request is made.
    //On page load, exactly the same code which is an external js in on of preceding script tags is used. 

    var arrowimages_new={down:['downarrowclass', 'category_parent_css_js/images/down.gif', 3], right:['rightarrowclass', 'category_parent_css_js/images/right.gif']}

    var jqueryslidemenu_new={

        animateduration: {over: 200, out: 100}, //duration of slide in/ out animation, in milliseconds

        buildmenu_new:function(menuid, arrowsvar){
            jQuery(document).ready(function($){
                var $mainmenu=$("#"+menuid+">ul")
                var $headers=$mainmenu.find("ul").parent()
                $headers.each(function(i){
                    var $curobj=$(this)
                    var $subul=$(this).find('ul:eq(0)')
                    this._dimensions={w:this.offsetWidth, h:this.offsetHeight, subulw:$subul.outerWidth(), subulh:$subul.outerHeight()}
                    this.istopheader=$curobj.parents("ul").length==1? true : false
                    $subul.css({top:this.istopheader? this._dimensions.h+"px" : 0})
                    $curobj.children("a:eq(0)").css(this.istopheader? {paddingRight: arrowsvar.down[2]} : {}).append(
                        '<img src="'+ (this.istopheader? arrowsvar.down[1] : arrowsvar.right[1])
                        +'" class="' + (this.istopheader? arrowsvar.down[0] : arrowsvar.right[0])
                        + '" style="border:0;" />'
                    )

                    $curobj.hover(
                        function(e){
                            var $targetul=$(this).children("ul:eq(0)")
                            this._offsets={left:$(this).offset().left, top:$(this).offset().top}
                            var menuleft=this.istopheader? 0 : this._dimensions.w
                            menuleft=(this._offsets.left+menuleft+this._dimensions.subulw>$(window).width())? (this.istopheader? -this._dimensions.subulw+this._dimensions.w : -this._dimensions.w) : menuleft
                            if ($targetul.queue().length<=1) //if 1 or less queued animations
                                $targetul.css({left:menuleft+"px", width:this._dimensions.subulw+'px'}).slideDown(jqueryslidemenu.animateduration.over)
                        },
                        function(e){
                            var $targetul=$(this).children("ul:eq(0)")
                            $targetul.slideUp(jqueryslidemenu.animateduration.out)
                        }                                               
                    ) //end hover
                }) //end $headers.each()
                $mainmenu.find("ul").css({display:'none', visibility:'visible', zIndex:'99999'})
                $mainmenu.find("ul li").css({zIndex:'99999'})
            }) //end document.ready
        }
    }

    //This function just sends an Ajax request.

    function getParentId(parentId)
    {
        $.ajax({
            datatype:"html",
            type: "GET",
            url: "ajax/ParentId.php",
            data: "ed_id=" + parentId+"&t="+new Date().getTime(),
            success: function(response)
            {       
                $('#originalMenu').html(response);
                jqueryslidemenu_new.buildmenu_new("myslidemenu", arrowimages_new);              
                //This calls the above function to pop up the menu.
            },
            error: function(e)
            {
                alert('Error: ' + e);
            }
        });
    }
</script>
</head>

<body>
<form action="" id="dataForm" name="dataForm" method="post">
  <table width="970" border="0" align="center" cellpadding="0" cellspacing="0">
    <tr>
      <td align="center" valign="middle" class="menu"><div id="header_top_menu">
          <div id="myslidemenu" class="jqueryslidemenu">
            <ul>
              <li>
                <div style='width:auto;cursor:hand;text-align:left; background-color:white; border:none; color:black; font-size:small;'>Menu 1</div>
                <ul>
                  <li><a href="#" onclick="getParentId(19); return false;">Menu Item 1</a>
                    <ul>
                      <li><a href="#" onclick="getParentId(21); return false;">Child Item 1</a></li>
                      <li><a href="#" onclick="getParentId(20); return false;">Child Item 2</a></li>
                      <li><a href="#" onclick="getParentId(20); return false;">Child Item 3</a></li>
                      <li><a href="#" onclick="getParentId(20); return false;">Child Item 4</a></li>
                      <li><a href="#" onclick="getParentId(20); return false;">Child Item 5</a></li>
                    </ul>
                  </li>
                </ul>
            </ul>
          </div>
        </div></td>
  </table>

  <br/><br/><br/><br/><br/>

  <table width="970" border="0" align="center" cellpadding="0" cellspacing="0">
    <tr>
      <td align="center" valign="middle" class="menu"><div id="header_top_menu">
          <div id="myslidemenu" class="jqueryslidemenu">
            <ul>
              <li>
                <div style='width:auto;cursor:hand;text-align:left; background-color:white; border:none; color:black; font-size:small;'>Menu 2</div>
                <ul>
                  <li><a href="#" onclick="getParentId(19); return false;">Menu Item 1</a>
                    <ul>
                      <li><a href="#">Child Item 1</a></li>
                      <li><a href="#">Child Item 2</a></li>
                      <li><a href="#">Child Item 3</a></li>
                      <li><a href="#">Child Item 4</a></li>
                      <li><a href="#">Child Item 5</a></li>
                    </ul>
                  </li>
                </ul>
            </ul>
          </div>
        </div></td>
  </table>
</form>
</body>
</html>

This HTML displays two menus, Menu 1 and Menu 2. When an item on Menu 1 clicked, an Ajax request is sent to a URL which does nothing in this demonstration. Both the menus are displayed properly before an Ajax request is made. Menu 1 is shown as follows.

enter image description here

Menu 2 is shown as follows (same as Menu 1).

enter image description here

Menu 1 is responsible to send an Ajax request which happens when an item of Menu 1 is clicked (which in this case does nothing. The page which this Ajax request is sent to is left blank entirely in this case. It's just a demonstration).

In both the cases, when mouse pointer is hovered over Menu Item 1, it opens up a sub menu which contains Child Item 1..... Child Item 5.

After an Ajax request is made, if I hover on Menu Item 1 of Menu 2, it doesn't function properly and looks something like the following.

enter image description here

When Menu Item 1 on Menu 2 is selected, the last sub menu of that parent menu (Menu Item 1) appears at once. Why does this happen?

On page load js code used to pop up the menu is as mentioned in the code imported as follows.

<script type="text/javascript" language="javascript" src="category_parent_css_js/cat_parent_js.js"></script>

which is exactly the same as the js code mentioned in code snippet. the js code in this snippet is used to pop up the menu after an Ajax request is made.


In case, if you were to need CSS, it is as follows which is linked by the following tag.

<link rel="stylesheet" type="text/css" href="category_parent_css_js/cat_parent.css" />

.jqueryslidemenu{font:bold 9px Tahoma, Verdana, sans-serif;color:#fff;width: 100%;text-align:left;z-index:99999}
.jqueryslidemenu ul{margin: 0;padding: 0px;list-style-type: none;z-index:99999}
.jqueryslidemenu ul li{position: relative;display: inline;float: left;z-index:auto}
.jqueryslidemenu ul li a{font:bold 12px Tahoma, Verdana, sans-serif;display: block;background:#000;color: #fff;padding: 3px 3px;text-decoration: none;z-index:99999}
* html .jqueryslidemenu ul li a{display: inline-block;z-index:99999}
.jqueryslidemenu ul li a:link, .jqueryslidemenu ul li a:visited{color: #fff;text-decoration: none;z-index:99999}   
.jqueryslidemenu ul li a:hover{background:#000;text-decoration:none;color: #03C;z-index:99999}
.jqueryslidemenu ul li ul{position: absolute;left: 0;display: block;visibility: hidden;z-index:99999}
.jqueryslidemenu ul li ul li{display: list-item;float: none;z-index:99999}
.jqueryslidemenu ul li ul li ul{top:0;z-index:99999}
.jqueryslidemenu ul li ul li a{font:bold 9px Tahoma, Verdana, Geneva, sans-serif;width: 140px;margin: 0;padding: 6px;border-top-width: 0;border-bottom: 1px solid gray;z-index:99999}
.jqueryslidemenuz ul li ul li a:hover{color:#fff; background:#000;z-index:99999}
.downarrowclass{position: absolute;top: 8px;right: 7px;display:none;z-index:99999}
.rightarrowclass{position: absolute;top: 6px;right: 5px;z-index:99999}
Tiny
  • 27,221
  • 105
  • 339
  • 599
  • Of course, I can but most of the HTML is generated dynamically and it is spread over more than on file so it's difficult to post such huge HTML code. – Tiny Oct 01 '12 at 18:53
  • if, on click, you call the function to popup the menu but skip the ajax call, do your results differ? – Asad Saeeduddin Oct 07 '12 at 20:00
  • @Asad - The menu(s) displays an n- level tree of various categories of various products. Initially all the menus are loaded on page load. **One fixed menu** of all of these menus when clicked, an Ajax request is made that highlights (colour is changed) the hierarchy of that category being clicked when the Ajax response is loaded. After that, the rest of the menus behave as mentioned in the question. Initially, they all are fine. If the Ajax call is skipped then there is no problem at all. Ajax is used here merely to show/highlight the hierarchy of the category being clicked which is required. – Tiny Oct 08 '12 at 04:14
  • Ok I understand that part. My question is this: if, instead of calling an ajax request on click and calling this function: 'jqueryslidemenu_new.buildmenu_new("myslidemenu", arrowimages_new);' in the success handler, you simply call this function in the click handler directly (with no ajax involved), do your results differ? The reason I ask is because while the ajax request doesn't actually do anything, the success handler does. The innerhtml for $(#originalMenu) is being set to blank here, for example. – Asad Saeeduddin Oct 08 '12 at 07:52
  • The menu is displayed using `
    • ` which is enclosed within a `
      ` tag with the `id` attribute `myslidemenu`. I have changed the `id` attribute for the menu which uses an Ajax call to `myajaxslidemenu` and simply call the jQuery function in the Ajax success handler with the new `id` like `jqueryslidemenu_new.buildmenu_new("myajaxslidemenu", arrowimages_new);` so that it doesn't affect the rest of the menus on the page. It works just fine now.
      – Tiny Oct 09 '12 at 15:05
  • JSBin with the HTML + CSS + JS, but it's not fully working -> http://jsbin.com/olemuj/1/, looks like there is something wrong with the JS – Cristiano Fontes Oct 10 '12 at 11:31
  • @Cfontes - It doesn't work there because it requires that js code on page load which is not available there. The js code seen here is used only with the Ajax call. On page load, it's however available through an external js file (exactly the same js code) ``. – Tiny Oct 10 '12 at 12:41
  • A good practice hint: Do terminate your javascript code lines with ; When I loaded your code up into my IDE it went berserk at me for all the missing ; Once I fixed all that I'll verify the issue. – IvanL Oct 11 '12 at 14:06
  • Allow me to add to that the issue that your HTML has missing closing tags and double IDs... I'd advise you to verify your rendering as well. Also the CSS pointer property takes "pointer", not "hand". – IvanL Oct 11 '12 at 14:13