Laoding Submenus via XML?

Are there constructs for (1) loading submenus via XML, or (2) loading both “top” and submenus via XML? The document at [url]http://dhtmlx.com/docs/products/dhtmlxMenu/doc/guide.html[/url] does not appear to demonstrate any such constructs. I have a grid with a context menu that includes a submenu that shows when a particular item was last updated (see below). To this point I’ve simply loaded the data into row attributes when the grid is loaded, and updated tghe submenu for each row when the context menu onRightClick even occurs. But, with the addition of inline row editing (i.e., via XML, no postback), the “last updated” information loaded with the grid is no longer current. As such, I need to be able to refresh the submenu via XML.


You may try to use dynamic loading:

docs.dhtmlx.com/doku.php?id=dhtm … al_loading

dhtmlx.com/docs/products/dht … namic.html

But the sub menu can be loaded only once. In order to force sub menu reloading you may try to use the following:

for example the “History” menu item has “history” id.

menu.attachEvent("onBeforeContextMenu",function(){ if(menu.itemPull[menu.idPrefix + "history") menu.itemPull[menu.idPrefix + "history"]["loaded"] = "no"; return true })

My first step was to get the entire menu and it’s single submenu loaded by XML program. I succeeded in that (as you would reasonably expect). Everything works as described in my original post. The load is accomplished by way of menu.loadXML(“TableMgrMenu.php?action=loadMenu”) and the onBeforeContextMenu that customizes the menu and submenu works fine. I then replaced the foregoing method with menu.enableDynamicLoading(“TableMgrMenu.php”,onBeforeContextMenu) (disabling the grid event reference to “onBeforeContextMenu” since the dynamic load is supposed to invoke that function when the menu is loaded). I can tell that the onBeforeContext is being executed, but – after way too much time trying to figure out why – the right-arrow is never appearing on the menu that’s supposed to have the fly-out submenu (“History”). I’ve tried it with and without the code you suggested, but no difference. In addition to this confusion on my part, I have another question: Is the dynamic load invoked once for each menu level? Or should the response include the entire menu structure, even if some submenu content will be refreshed (as per your suggested approach)? I tried presenting the entire content and, as I noted above, I couldn’t get the submenu to be accessible.

Here’s what the entire structure looks like (and I should note that I also tried including complex=yes for the menuHistory entry):

[code] <?xml version="1.0" encoding="ISO-8859-1" ?>

  • [/code]

And when including a parentId:

[code] <?xml version="1.0" encoding="ISO-8859-1" ?>

  • [/code]

The second parameter of enableDynamicLoading is true or false value (it replaces an element arrow with loading image while loading);

Instead of type=“complex” there should be complex=“true”

I’ve attached the working demo
02.zip (38.3 KB)

It took me a while to realize that the “onBeforeContextMenu” event referenced in your example was attached to the Menu object. I have an “onBeforeContextMenu” attached to the Grid as well, and it is in this event handler that I decide which level 1 menu options should be enabled or disabled, and I also update the single submenu we’ve been looking at.

With your help I am now successfully loading the menu structure by way of XML/Ajax. However there still appear to be some issues.

  1. I set the second enableDynamicLoading argument to “true”, but I’m not seeing any “in progress” image. I suspect this is because, as I’m testing on localhost, the turnaround is too fast to warrant this appearing.

  2. Following your suggestion, I added this following:

menu.attachEvent("onBeforeContextMenu", function() { alert(menu.itemPull[menu.idPrefix + 'menuHistory']); if (menu.itemPull[idPrefix + 'menuHistory']) { menu.itemPull[idPrefix + 'menuHistory']['loaded'] = 'no'; return true; } } ); enableDynamicLoading("TableMgrMenu.php",true); It now appears that
(A) the very first time the submenu is invoked, it is not updated at all by the code in the Grid’s onBeforeContextMenu event handler. I.e, the items’ text is exactly as issued by TableMgrMenu.php. I confirmed that update code in indeed executing, by adding an alert at the end. I assume that what’s happening here is that what the Grid’s event handler does is replaced by what comes from TableMgrMenu.php via parentId.
(B) Subsequently all submenu displays are filled in with data relevant to each row, but it is clear that the submenu “template” is never again loaded via TableMgrMenu.php/parentId. (I used your suggestion and added a random number to the XML “template.”)
© I should also note that the alert you see included in the Menu onBeforeContextMenu handler is never triggered.

Overall I suspect some timing issues. If I could ensure that the submenu is reloaded at each invocation, I would assume that any fiddling around with that menu’s images or item text would have to be done in an onXLE event handler for the submenu.

set the second enableDynamicLoading argument to “true”, but I’m not seeing any “in progress” image.

Locally the image is shown but loading is too fast to see it. I’ve placed alert to catch the image. Sample is attached

Regarding the second problem - it isn’t clear for me. I need a complete demo. But please don’t include the grid libraries (context menu is the part of PRO edition).
02.zip (38.3 KB)

I have made some progress. I found some minor differences between my XML-generation and that included with your example. But that had practically no affect at all until I took a wild guess that perhaps there’s a conflict, or more appropriately stated, an overlap, between a “Menu” onBeforeContextMenu and a “Grid” onBeforeContextMenu. When I placed the “itemPull” logic into the onBeforeContextMenu function assigned to the “Grid” I was able to mimic the example you provided, indeed seeing the submenu reloaded.

Having said that, allow me to point out a small problem with the submenu not being cleared when successive right clicks are done. See screenshot below, based on the “02.zip” content you sent (modified with a random # in the “Edit” menu):


I assume this is probably a fairly easy thing to address.

Finally, let me ask one more question. Is there a way for me to pass a parameter to the dynamic load URL? (E.g., menu.php?key=123, where the key value is, for example, pulled from a row attribute.) When the submenu XML is generated, I’d like to populate it with some database information specific to the grid row.

We have made another demo. The dynamic loading isn’t used here.

Menu is reloaded on “onBeforeContextMenu” event:

  • clearAll method clears menu
  • loadXMLString loads new items.
    Also we added caching for grid rows. In order to not load the same xml several times.
    94.zip (40.5 KB)

This is —> OUTSTANDING. It works great! Menu and submenu are dynamically loaded, and “on the fly” modified with data retrieved from the database. Thanks!

The approach has been working out like a champ. I do have a follow-up question, though.

Is there a way, either in the program that generates the XML data for the menu, or by examining the resultant menu in the “menu is now reloaded” event handler, to still cancel the menu display. The reason for asking is: the PHP program I have that generates the menu content makes decisions on whether an item is to be included or excluded, and if included, enabled or disabled. It is possible that all menu items included are set disabled. In such a scenario, why even display the menu at all?

if you want to not show the menu when all items are disabled, you may try using teh following:

[code]menu.attachEvent(“onBeforeContextMenu”,function(){
var rId = Math.ceil(Math.random()*20);
if (!xmlCache[rId]) xmlCache[rId] = (dhtmlxAjax.getSync(“menu.php?rId=”+rId+"&etc="+new Date().getTime())).xmlDoc.responseText;
menu.clearAll();
menu.loadXMLString(xmlCache[rId]);

    var show = false;
menu.forEachItem(function(id){
	if(menu.isItemEnabled(id)) show = true;
})
return show;

});[/code]

Thanks, Alexandra. I am aware that the context menu display can be canceled in the “onBeforeContextMenu” event handler. In some cases I already do this.

I apologize for failing to properly explain the scenario I’m inquiring about.

The context of my question is the event that is invoked after dynamically re-loading the context menu via XML. (I referred to this in my previous post as the “menu is now reloaded” event handler.)

In other words:

  • The onBeforeContextMenu code invokes a dynamic reload via XML (with a callback to the “menu is now reloaded” code),
  • The PHP program that constructs the menu’s XML does so (with, as it turns out, the net result being that all menu inclusions are disabled),
  • Control returns to the “menu is now loaded” code.

It is at this point I am not aware of a mechanism that allows for the menu display to be canceled.

There are two ways not to show content menu:

  • to hide context menu after it is shown:

menu.hideContextMenu();

  • to block menu by onBeforeContextMenu event.

Thanks for directing my attention to the hideContextMenu method. While it does not resolve the issue, testing it did reveal some other areas of code I needed to address – unrelated to the issue.

The reason for the hideContextMenu not working may be that the menu is not yet displayed when I determine that all top-level items are disabled. Here’s some pseudo-code that describes what I’d like to accomplish:

[code]function onContextMenu_handler(rowId, colIndex, gridObject) {

menu.clearAll();
menu.loadXMLString(myURL, onMenuReloaded_handler);
return true;
}

function onMenuReloaded_handle(rowId){

enabledCount = 0;
menu.forEachItem(function(id){
if (
menu._getItemLevelType(id).toLowerCase() == ‘toplevel’
&&
menu.isItemEnabled(id)
&&
menu.getItemType(id).toLowerCase() != ‘separator’
)
{enabledCount++}
});
if (enabledCount == 0) {menu.hideContextMenu()}
}[/code]
At the point of the call to hideContextMenu, the menu is not displayed. I verified this by placing an alert immediately after the hideContextMenu. When the alert is shown, there is no menu displayed.

When the onContextMenu_handler function is called ? if it is called from the onBeforeContextMenu event, why don’t you want to block this event (return false) ?

hideContextMenu hides menu if the menu is already visible.

Because at the time the onContextMenu handler is executed (when the opportunity to return false does exist), it has not yet been determined what menu items will or will not be enabled. The PHP program that generates the XML, invoked as described above, makes such decisions based upon a database query. As such, it is desirable to be able to also decide in the onMenuReloaded_handler (as referred to above) whether to proceed with the context menu display. Apparently this capability is not present.

menu.loadXMLString(myURL, onMenuReloaded_handler);

loadXMLString doesn’t require using loading end handler. As the data are not loaded asynchronously from server in this case.

In the example I sent you before items are loaded synchronously. So, it is possible to return false from the onBeforeContextMenu event handler.

Thanks for the info. It works exactly as desired!