Creating popup menus in JQuery Mobile is not quite simple. I am talking about menu that you might want to display when user clicks on, for example, a list item or a button. Refer to JQuery Mobile documents for select menus and custom menus . These menus are actually drop down lists and in all the cases, the menu has to be already visible.
However this is not what I wanted in my mobile apps. I do not want menu to be visible initially, but want to display it when user clicks on a button on a list item. So I started investigating how this could be done. As it turned out, the menu that JQuery Mobile shows (when nativeMenu attribute is set to false), is different from the select tags that you create for the menu. JQM hides the menu that you create and creates a new (wrapper) menu using div and anchor tags. Option tags become anchor tags in the new menu. This is all fine, but the problem is that JQM does not have any direct APIs to access elements of the new menu. This makes it difficult to attach event handlers to menu options.
But JQM follows certain patterns when creating the wrapper menu. As of the current version, which is 1.1, JQM does following –
- It creates an outer div with ui-selectmenu class
- Within the above div it creates ul element with id = id_of_the_select_element + “-menu”
- It creates li element for each menu option inside the above ul element
- Actual menu items are in anchor element inside the above li element
All this is not documented by JQuery Mobile, so it might change in the future versions.
So, having understood the above pattern, it was then easy to create a menu and attach event handler. Here is a simple example, which displays a menu when a button is clicked –
First a screen shot –
<!DOCTYPE html> <html> <head> <link type="text/css" href="jquery.mobile-1.2.0.css" rel="stylesheet"> <script type="text/javascript" src="jquery-1.8.2.js"></script> <script type="text/javascript" src="jquery.mobile-1.2.0.js"></script> <script type="text/javascript"> $(document).bind("pageinit", onPageInit); //variable to store menu instance newMenu = null; function onPageInit() { //create menu. First option in the third argument is menu title createMenu("dynamicMenu1","contentDiv","Menus,menu1,menu2,menu3",menuHandler); $("#btn1").click(function(){ showMenu(newMenu); }); } function createMenu(menuId, parentId, options, menuHandler) { //create a containing div var div = $("<div id='" + menuId + "div'></div>").appendTo("#"+parentId).hide(); //create select tag var menuElm = $("<select id='" + menuId + "' data-inline='true' data-native-menu='false'></select>").appendTo(div); //add options var optionsArray = options.split(","); for (var i = 0; i < optionsArray.length; i++) $("<option>" + optionsArray[i] + "</option>").appendTo("#"+menuId); //convert to JQueryMobile menu $("#" + menuId).selectmenu(); //find custom menu that JQM creates var menus = $(".ui-selectmenu"); for (var i = 0; i < menus.length; i++) { //if ($(menus[i]).children("ul:#" + menuId + "-menu").length > 0) if ($(menus[i]).children("ul").filter("#" + menuId + "-menu").length > 0) { newMenu = $(menus[i]); break; } } //Hack for JQM 1.2 - check if parent of select menu is ui-popup-container var menuContainer = $(menus).parent(".ui-popup-container"); if (menuContainer.length > 0) { var pageElm = menuContainer.parent("div[data-role='page']"); if (pageElm.length > 0) { menus.detach(); menuContainer.remove(); pageElm.append(menus); menus.css("width", "80%"); menus.css("max-width", "350px"); } } if (newMenu == null) { alert("Error creating menu"); return; } //Associate click handler with menu items, i.e. anchor tags $(newMenu).find(".ui-selectmenu-list li a").click(menuHandler); //Add Close option var menuHeader = $(newMenu).find(".ui-header"); var closeLinkId = menuId + "_close_id"; menuHeader.prepend("<span style='position:relative;float:left'>" + "<a href='#' id='" + closeLinkId + "'>X</href></span>"); $("#" + closeLinkId).click(function(e){ newMenu.hide(); }); return newMenu.hide(); } function showMenu(menu) { if (menu == null) return; //show menu at center of the window var left = ($(window).width() - $(menu).width()) / 2; //consider vertical scrolling when calculating top var top = (($(window).height() - $(menu).height()) / 2) + $(window).scrollTop(); $(menu).css({ left: left, top: top }); $(menu).show(); } //Callback handler when menu item is clicked function menuHandler(event) { if (newMenu != null) $(newMenu).hide(); alert(event.srcElement.text); } </script> </head> <body> <div data-role="page" > <div data-role="content" id="contentDiv"> <a href="" data-role="button" data-inline="true" id="btn1">Show Menu</a> </div> <span style='position:relative;float:left'></span> </div> </body> </html>
– Ram Kulkarni


Leave a Reply