views:

19

answers:

1

Hi all,

I'm doing a menu that loads levels dynamicly, when you click on a item the next level is loaded asynchronously. For each menu item I have a user control. Every user control is declared in its parent, for example, the "secondlevelcontrol" has the reference to "thirdlevelcontrol".

With this level of nesting, I want to manage the asynchronous calls on every user control so, when the first level is loaded the javascript to load the second is loaded too. When the second level is loaded the javascript to load the third is loaded too.

To do asynchronous calls I'm implementing ICallbackEventHandler interface. As you can see in the examples, controls are added to the page as plain html. The method "ProcessOnLoadEvent" executes all lines of the "OnLoad" event of the user control.

An example of the implementation is this for the user control of fourth level:

public string GetCallbackResult()
{
    return _callbackRendering;
}

public void RaiseCallbackEvent(string itemId)
{
    var id = Int32.Parse(itemId);
    var menu = new LateralMenu();
    var currentChildren = menu.GetNodesById(id, 1);

    var ctrl = this.Page.LoadControl(USER_CONTROL_FIVE_LEVEL_RELATIVE_PATH) as LeftSideFifthLevel;
    ctrl.Items = currentChildren.Children;
    ctrl.ProcessOnLoadEvent();

    _callbackRendering = ctrl.GetHtml();
}

And this is the code for the fifth level user control:

public void ProcessOnLoadEvent()
{
    EnsureChildControls();

    if (null != RepeaterMenu)
    {
        SettingCallbackReference();

        Visible = null != Items && 0 < Items.Count;

        if (null != Items && 0 < Items.Count)
        {
            RepeaterMenu.DataSource = Items;
            RepeaterMenu.DataBind();
        }
    }
}

public void RaiseCallbackEvent(string itemId)
{
    var id = Int32.Parse(itemId);
    var menu = new LateralMenu();
    var currentChildren = menu.GetNodesById(id, 1);

    var ctrl = this.Page.LoadControl(USER_CONTROL_SIX_LEVEL_RELATIVE_PATH) as LeftSideSixthLevel;
    ctrl.Items = currentChildren.Children;
    ctrl.ProcessOnLoadEvent();

    _callbackRendering = ctrl.GetHtml();
}

public void SettingCallbackReference()
{
    var cm = this.Page.ClientScript;
    var cbRef = cm.GetCallbackEventReference(this, "itemId", "AnchorLevel5_OnClick_Callback", "ctx");
    var cbScript = "function AnchorLevel5_OnClick(itemId, ctx){ new Menu().empty(ctx); " + cbRef + "; }";
    cbScript += "function AnchorLevel5_OnClick_Callback(htmlText, ctx){ new Menu().render(htmlText, ctx); }";
    cm.RegisterClientScriptBlock(this.GetType(), "CallServer", cbScript, true);
}

My problem is that levels beyond second level never work because the javascript associated with the user control ("SettingCallbackReference" method) has no html to put on the page.

Is there any way to create some user controls created dynamicly that implements ICallbackEventHandler interface that add new user controls to the page? Or, Am I doing something wrong and this is not the right way to implement this behaviour?

Thanks!!!

A: 

I suspect that you are probably going about this the wrong way. Take a look at the answer to this question: http://stackoverflow.com/questions/3333324/how-to-lazy-load-infragistics-ultrawebtree-control

This question was specifically about lazy-loading a tree view, but the same principles apply for lazy loading menu items. Follow these steps:

  1. On first page load, render the top level menu
  2. Include a function on the page that makes an ajax call to the server with the parent id and retuns the next level items for that parent (getNodes in my example)
  3. Bind this function to the click event of the top level menu items (that have sub items)
  4. In the success handler of the ajax call, inject the returned menu items below the parent and bind the same function to the click event of these items only.

On callback, be careful not to bind the function to the click event of ALL menu items, because then you will end up getting the function bound multiple times to the top level items and called multiple times. Just bind to the returned items.

Also, you need some way of determining that an item's sub items have already been loaded. That is what the following line in my example was for, but you might need something slightly different:

 if (jQuery(nodesDiv).text() == 'Loading...') {

I used jQuery because it is the most concise, but you culd do this in pure js - I wouldn't recommend it.

Daniel Dyson
Good answer but I can't create web services. I want to use ICallbackEventHandler to do this though I think is something wrong on my approach.
jaloplo
You could just use a webmethod on your page. You don't need to create a separate webservice.
Daniel Dyson