[CLOSED] Loader with Html renderer and Window rendering

Page 1 of 4 123 ... LastLast
  1. #1

    [CLOSED] Loader with Html renderer and Window rendering

    Hi,

    I'm trying to use the Html mode of the loader within a panel. This works fine on first load, but subsequent loads corrupt any windows that have been rendered previously. From digging around with this it appears that any windows are rendered to the end of the document body rather than the place holder for the loaded content. So ,for a panel it's fine because it renders to the place holder and then on reload that DOM element is replaced with the new panel. But any windows have been rendered to the document body and so on reload they still exist as they haven't been replaced causing issues that are similar to ID conflicts.

    Please see test case below:

    Parent View:
    <%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
    
    
    <!DOCTYPE html>
    <html>
    <head runat="server">
        <title>ViewParent</title>
        <ext:ResourceManager runat="server" ID="ParentResourceManager">
        </ext:ResourceManager>
    </head>
    <body>
        <ext:Viewport runat="server" Layout="FitLayout">
            <Items>
                <ext:Panel ID="PanelShellLoaderHtml" runat="server" Layout="FitLayout">
                    <TopBar>
                        <ext:Toolbar runat="server">
                            <Items>
                                <ext:Button runat="server" Text="Refresh" OnClientClick="#{PanelShellLoaderHtml}.loader.load();"></ext:Button>
                            </Items>
                        </ext:Toolbar>
                    </TopBar>
                    <Loader ID="Loader1" runat="server" Url='<%# Url.Action("ViewChild") %>' AutoDataBind="True"  Mode="Html" Scripts="True">
                        <LoadMask ShowMask="True" />
                    </Loader>
                </ext:Panel>
            </Items>
        </ext:Viewport>
    </body>
    </html>
    Child View
    <%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
    
    
    <!DOCTYPE html>
    <html>
    <head runat="server">
        <title>ViewParent</title>
        <ext:ResourceManager runat="server" ID="ParentResourceManager" RenderScripts="None"
            RenderStyles="None">
        </ext:ResourceManager>
    </head>
    <body>
        <ext:Window ID="Window1" runat="server" Title="This is the window" Width="400" Height="500">
        </ext:Window>
        <ext:Panel runat="server" Title="Main Panel" Layout="FitLayout">
        </ext:Panel>
    </body>
    </html>
    If you run this you'll see the window appear fine on the first load, but clicking refresh in the toolbar will cause the window to corrupt. Removing the window ID cause it to use a generated ID will work as there is no conflict. But I think this is still a bug as the document is never cleaned up and will leak these components, plus INamingContainer style names are not acceptable as I have a lot of custom client script which expects the Id's to be static.

    Hope you can help.
    Last edited by Daniil; Jul 02, 2013 at 4:02 AM. Reason: [CLOSED]
  2. #2
    Hi,

    Well, Loader knows nothing about the content which it loads, so, it can't remove it automatically before "refresh".

    I would suggest you to use partial views.
  3. #3
    Hi Daniil, sorry to disagree but the Html renderer uses replace to remove and then replace the content loaded via XHR. That's why the panel isn't a problem, it's just the Window components that get rendered to the end of the body are in the wrong place to be replaced.
  4. #4
    OK, some more thought... If I set the renderTo explicitly to the element generated to hold the content then it works. Question now is - is there a way to determine this name or a property that can be set to dictate this behaviour?

    Any help much appreciated!


    <%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
    
    
    <!DOCTYPE html>
    <html>
    <head runat="server">
        <title>ViewParent</title>
        <ext:ResourceManager runat="server" ID="ParentResourceManager">
        </ext:ResourceManager>
    </head>
    <body>
        <ext:Viewport runat="server" Layout="FitLayout">
            <Items>
                <ext:Panel ID="PanelShellLoaderHtml" runat="server" Layout="FitLayout">
                    <TopBar>
                        <ext:Toolbar runat="server">
                            <Items>
                                <ext:Button runat="server" Text="Refresh" OnClientClick="#{PanelShellLoaderHtml}.loader.load();">
                                </ext:Button>
                            </Items>
                        </ext:Toolbar>
                    </TopBar>
                    <Loader ID="Loader1" runat="server" Url='<%# Url.Action("ViewChild") %>' AutoDataBind="True"
                        Mode="Html" Scripts="True">
                        <LoadMask ShowMask="True" />
                    </Loader>
                </ext:Panel>
            </Items>
        </ext:Viewport>
    </body>
    </html>
    <%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
    
    
    <!DOCTYPE html>
    <html>
    <head runat="server">
        <title>ViewParent</title>
        <ext:ResourceManager runat="server" ID="ParentResourceManager" RenderScripts="None"
            RenderStyles="None">
        </ext:ResourceManager>
    </head>
    <body>
    
    
        <ext:Window ID="win1" runat="server" Title="This is the window" Width="400" Height="500"
            RenderTo="PanelShellLoaderHtml-body">
        </ext:Window>
        <ext:Panel runat="server" Title="Main Panel" Layout="FitLayout">
            <Content>
            </Content>
        </ext:Panel>
    </body>
    </html>
  5. #5
    Hi, I've just tried using a partial view as suggested but this has the same result. Any content in the partial view is replaced as expected when reloaded with the exception of any Window components which persist after reload.
  6. #6
    Quote Originally Posted by paulc View Post
    Hi Daniil, sorry to disagree but the Html renderer uses replace to remove and then replace the content loaded via XHR. That's why the panel isn't a problem, it's just the Window components that get rendered to the end of the body are in the wrong place to be replaced.
    Mode="Html" doesn't destroy components. It just:

    1. Executes the scripts from a response if Scripts="true".
    2. Replace container body HTML with a new one from a response.

    The second doesn't mean the rendered components will be destroyed. It replaces just HTML.

    For example, imagine there is "Panel1" in the child page which is loaded initially. Then you load some other page:
    #{PanelShellLoaderHtml}.load({ url : 'Test2.aspx'});
    with no Panel1.

    The new page will replace the old container content, but you will be still able to access the Panel1 component which was rendered initially.

    One more disadvantage of Mode="Html" - components from a child page won't participate in layout logic of a parent container. They will considered just as raw HTML.

    I've just tried using a partial view as suggested but this has the same result.
    I would suggest to place the Window into Bin of the Panel. Here is more details about the Bin feature.
    http://forums.ext.net/showthread.php...ll=1#post57259

    Here is the example how I would implement your requirement.

    Example Main View
    <%@ Page Language="C#" %>
    
    <%@ Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>
     
    <!DOCTYPE html>
    
    <html>
    <head runat="server">
        <title>Ext.Net.MVC v2 Example</title>
    </head>
    <body>
        <ext:ResourceManager runat="server" />
        <ext:Viewport runat="server" Layout="FitLayout">
            <Items>
                <ext:Panel ID="Panel1" runat="server" Layout="FitLayout">
                    <TopBar>
                        <ext:Toolbar runat="server">
                            <Items>
                                <ext:Button runat="server" Text="Refresh">
                                    <Listeners>
                                        <Click Handler="#{Panel1}.reload();" />
                                    </Listeners>
                                </ext:Button>
                            </Items>
                        </ext:Toolbar>
                    </TopBar>
                    <Loader 
                        runat="server" 
                        Url="/Test/PartialView1"
                        Mode="Html" 
                        Scripts="True">
                        <LoadMask ShowMask="True" />
                        <Params>
                            <ext:Parameter Name="containerId" Value="this.target.nsId" Mode="Raw" />
                        </Params>
                    </Loader>
                </ext:Panel>
            </Items>
        </ext:Viewport>
    </body>
    </html>
    Example Partial View
    <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
    
    <%@ Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>
    
    <ext:Panel 
        ID="PanelPartialView"
        IDMode="Static"
        runat="server" 
        Html="I participate in layout. I am stretched according to FitLayout." 
        BodyStyle="background-color: yellow;">
        <Bin>
            <ext:Window 
                ID="WindowPartialView" 
                runat="server" 
                Html='<%# DateTime.Now.Second %>' 
                AutoDataBind="true" />
        </Bin>
        <Listeners>
            <AfterRender Handler="this.bin[0].show();" />
        </Listeners>
    </ext:Panel>
    Example Controller Action
    public ActionResult PartialView1(string containerId)
    {
        Ext.Net.MVC.PartialViewResult r = new Ext.Net.MVC.PartialViewResult();
        r.ContainerId = containerId;
        r.RenderMode = RenderMode.AddTo;
        r.SingleControl = true;
    
        return r;
    }
  7. #7
    Hi Daniil, thank you for your suggestions, I will investigate these now. One thing to mention though is that I updated from SVN this morning and Vladimir made some changes this morning which appear to have fixed the rendering issue.

    However, I am now considering whether this approach is usable at all because of the memory leak you refer to with regards to references to the components remaining. I will do some memory profiling and see what the result is, but I'm now at a point where I may have to rethink the whole approach. Another "murky" area I have is that I need to load content in Frame mode if it is legacy code or in Html mode if it is Ext.net by switching the renderer.
    e.g. usage:
    ...
                listeners: {
                    afteranimate: function () {
                        window.App.PanelShellLoader.loader.load({ url: menuItem.Url, renderer: menuItem.Mode.toLowerCase() });
                    }
                }
    ...
    I had a few problems getting this to work and came up with the following override. Could you cast your eye over it in case I've missed something?

    TIA

    Ext.override(Ext.net.ComponentLoader,
    {
        load: function (options) {
            if (Ext.isString(options)) {
                options = { url: options };
            }
            else {
                options = Ext.apply({}, options);
            }
    
    
            if (this.paramsFn) {
                this.params = this.paramsFn();
            }
    
    
            if (options.paramsFn) {
                options.params = Ext.apply(options.params || {}, options.paramsFn());
            }
    
    
            if (!Ext.isDefined(options.passParentSize) && this.passParentSize) {
                options.params = options.params || {};
                options.params.width = this.target.body.getWidth(true);
                options.params.height = this.target.body.getHeight(true);
            }
    
    
            if (!Ext.isEmpty(this.target.iframe) && options.renderer != "frame") {
                this.target.removeAll(true);
                this.target.iframe = null;
            }
    
    
            if (options.renderer == "frame") {
                this.loadFrame(options);
                return;
            }
    
    
            if (this.directMethod) {
                var me = this,
                    mask = Ext.isDefined(options.loadMask) ? options.loadMask : me.loadMask,
                    params = Ext.apply({}, options.params),
                    callback = options.callback || me.callback,
                    scope = options.scope || me.scope || me,
                    method,
                    dmCfg;
    
    
                Ext.applyIf(params, me.params);
                Ext.apply(params, me.baseParams);
    
    
                Ext.apply(options, {
                    scope: me,
                    params: params,
                    callback: me.onComplete
                });
    
    
                if (me.fireEvent('beforeload', me, options) === false) {
                    return;
                }
    
    
                if (mask) {
                    me.addMask(mask);
                }
    
    
                method = Ext.decode(this.directMethod);
    
    
                dmCfg = {
                    complete: function (success, result, response) {
                        me.onComplete(options, success, { responseText: result });
                    }
                }
    
    
                if (method.length > 1) {
                    method(Ext.encode(options.params), dmCfg);
                }
                else {
                    method(dmCfg);
                }
    
    
                me.active = {
                    options: options,
                    mask: mask,
                    scope: scope,
                    callback: callback,
                    success: options.success || me.success,
                    failure: options.failure || me.failure,
                    renderer: options.renderer || me.renderer,
                    scripts: Ext.isDefined(options.scripts) ? options.scripts : me.scripts
                };
    
    
                me.setOptions(me.active, options);
    
    
                return;
            }
    
    
            Ext.net.ComponentLoader.superclass.load.apply(this, arguments);
        }
    });
  8. #8
    Quote Originally Posted by paulc View Post
    Hi Daniil, thank you for your suggestions, I will investigate these now. One thing to mention though is that I updated from SVN this morning and Vladimir made some changes this morning which appear to have fixed the rendering issue.
    Yes, he has added the feature of "auto-destroying" components. A component checks before creating any other component with the same id exists. If exists, then the component removes this "previous" component. And yes, it should fix your initial issue.

    But it's a bit experimental feature in the context of Beta release. We might give it up for the final release if there will be any problems (we are just not sure at the moment what backstage effects may be caused by this feature).

    Explicit destroying would be the best choice.

    In addition, the following example is marked with "an experimental example".
    https://examples2.ext.net/Default.as...der_Html_Mode/

    So, we would still don't recommend to use it in a real application. At least, in the case when you need Ext.NET control in a child page.

    Quote Originally Posted by paulc View Post
    Another "murky" area I have is that I need to load content in Frame mode if it is legacy code or in Html mode if it is Ext.net by switching the renderer.
    e.g. usage:
    ...
                listeners: {
                    afteranimate: function () {
                        window.App.PanelShellLoader.loader.load({ url: menuItem.Url, renderer: menuItem.Mode.toLowerCase() });
                    }
                }
    ...
    I had a few problems getting this to work and came up with the following override. Could you cast your eye over it in case I've missed something?
    Could you please start a new forum thread? Please provide more details about the initial problem with switching renderers.
  9. #9
    Auto-destroy sounds like a very neat idea, I hope it works out. I did do some profiling and your 100% correct there is a memory leak when I reload the content. I also checked a standard partialview invoked via a directmethod and to my surprise that also leaks, I kind of thought that was a pretty safe thing to do? Is this also a known limitation of partialview rendering?

    Click image for larger version. 

Name:	profile.png 
Views:	548 
Size:	31.0 KB 
ID:	4260

    My Window markup in the partial view is:

    <ext:Window runat="server" ID="windowPreview" Title="Asset Details" Width="750" Height="650"
        Maximizable="true" Layout="BorderLayout" CloseAction="Destroy" Closable="True"
        Modal="True">
    ...
    </ext:Window>
  10. #10
    Quote Originally Posted by paulc View Post
    I also checked a standard partialview invoked via a directmethod and to my surprise that also leaks, I kind of thought that was a pretty safe thing to do? Is this also a known limitation of partialview rendering?
    To get the controls from a partial view destroyed, there must be the same id of a new rendered control (after refreshing).

    I've achieved that in my example by setting
    IDMode="Static"
    for the top level Panel.
Page 1 of 4 123 ... LastLast

Similar Threads

  1. [CLOSED] ext:Window Loader Autosize
    By supera in forum 2.x Legacy Premium Help
    Replies: 9
    Last Post: Sep 05, 2016, 7:07 PM
  2. Replies: 5
    Last Post: May 18, 2012, 1:41 PM
  3. [CLOSED] Rendering html in a user control
    By fordprefect in forum 1.x Legacy Premium Help
    Replies: 4
    Last Post: Mar 14, 2012, 7:42 PM
  4. [CLOSED] Getting the parameter defined in ext:Window Loader
    By supera in forum 2.x Legacy Premium Help
    Replies: 5
    Last Post: Feb 17, 2012, 1:27 PM
  5. Replies: 1
    Last Post: May 28, 2010, 1:13 PM

Tags for this Thread

Posting Permissions