GridPanel -> Editable -> Master Page issue

  1. #1

    GridPanel -> Editable -> Master Page issue

    Hello. I just installed Ext.Net 5.2.0.

    I was trying to implement the GridPanel - > Editable - > Editor with DirectMethod.

    I copied the example and it worked fine with a standalone .aspx page (.net 4.7.2)

    When I tried to implement the example using Master page - it did not work.

    My child TestMaster.cs file has the exact copy of server side stuff from the example.

    My child TestMaster.aspx has GridPanel defined within <asp:Content...>

    <asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
            
            <h1>Editable GridPanel With Save To [DirectMethod]</h1>
    
            <ext:GridPanel
                ID="GridPanel1"
                runat="server"
    ..........................

    My Master SiteMaster.aspx Page has the following:

        <form runat="server">
            <ext:ResourceManager runat="server" SourceFormatting="true" />
            <asp:ScriptManager runat="server" EnablePageMethods="true" EnablePartialRendering="true" >
                <Scripts>
                    <asp:ScriptReference Path="~/Scripts/ExtNet/PageFunctions.js" />
                </Scripts>
            </asp:ScriptManager>
    ....................
    Where "PageFunctions.js" has the java script from example that calls CompanyX.Edit

    I verified that the js code is being called (by putting alerts) when the cell in GridPanel is changed/tabbed out.

    It looks like it is having trouble calling CompanyX.Edit(xxx) function.


    I also tried to add GridPanel to existing application page (using same Master etc). Getting a different error there.

    I will attach both errors.

    Thanks in advance.
    Attached Thumbnails Screen Shot 2020-05-22 at 1.21.09 PM.png   Screen Shot 2020-05-22 at 1.05.55 PM.jpg   Screen Shot 2020-05-22 at 1.06.07 PM.jpg  
    Last edited by fabricio.murta; May 25, 2020 at 4:04 PM. Reason: Format message
  2. #2
    Hello @Dennis, and welcome to Ext.NET forums!

    I see by your second and third screenshot an issue that doesn't look like something related to Ext.NET, but by some kind of mishap with ASP.NET session state manager. I think you should look that up. Somehow it only triggers when you include the master page to the process.

    This example is not too big, is it? I believe you can just paste your version of the master page and the child page so we can test in out side and see what's going on. If in doubt, I will point three threads that guides with this process in the bottom of this post.

    It seems you created your grid panel in the master page, then I don't think your "slave page" is going to see the grid store defined in its master, is it? I mean, the store's very data binding should fail as Store1 won't be present in the slave page's Page_Load() event.

    If you switched from the simple standalone to a very complex master page model (with, say, all your application's features), I advise you to take a step back and iteractively develop your simple > master page example.

    Iterate through something like:
    1. the standalone simple example (which you noted already works for you)
    2. simple master page just wrapping the example (all defined still in the "slave page")
    3. move the javascript functions out with the asp:scriptManager concept you require
    4. define the grid panel in the master page.
    5..n. iterate through the features of your project, always ensuring all works each new feature you add.

    I think this way will be much easier for you to identify what's breaking each step you take.

    Hope this helps!

    -- the topics I promised --
    - Tips for creating simplified code samples
    - More Information Required
    - Forum Guidelines
    Fabrício Murta
    Developer & Support Expert
  3. #3
    Fabricio, thanks for getting back to me!.
    Actually I did define the grid in the slave page TestMaster.aspx and later on I moved the <ext:ResourceManager...> from Master page to TestMaster as well.

    Out Master page is not complicated - it just has the overall site layout and really no functionality, but I will try to create another one with pretty much nothing and see if that causes any issues.

    Thanks,
    Dennis.
  4. #4
    Hello,
    I created a simple Master page example, now the saving feature is working, but it does not seem the combo box javascript renderer function can be found (it is located in the same script file).

    ...
                        <ext:Column runat="server" DataIndex="TransferStatus_ID" Text="Status Select" Width="200">
                            <Renderer Fn="statusRenderer"></Renderer>
                            <Editor>
                                <ext:ComboBox ID="cbStatuses" StoreID="StoreCombo" DisplayField="Name" ValueField="ID" runat="server" />
                            </Editor>
                        </ext:Column>
    ...
    this causes the whole field to be missing data.

    All above works in the standalone page without any issues.

    Is there something specific about how renderer functions are called that I am missing? I tried to include the js file within master page both ways (script manager and reference in the <head> tag) with the same result. I would like to submit an example. how would you like me to do that considering there is Slave Page, Master Page, Javascript File. Include each one in [code] blocks?

    Thanks,
    Dennis.
    Last edited by Dennis; Jun 29, 2020 at 7:58 PM.
  5. #5
    Hello @Dennis!

    There are some nice test cases with master page shared in the forums, if you search google for: site:forums.ext.net master page;

    To name a couple:
    - Layout Design using Master page
    - Master Page and height of CalendarPanel in child page

    The JavaScript can be inlined in the page where it is included, like:

    <script type="text/javascript">
        Ext.toast("My script here.");
    </script>
    Supposing you properly simplified the test case each file should not be much longer than the ones in the examples above. If not, I'm sure there are still artifacts you can remove from the page and still reproduce the issue without the need to paste a several-pages-long code block pair.

    Hope this helps!
    Fabrício Murta
    Developer & Support Expert
  6. #6
    Hi Fabricio, I looked at the examples you provided but unfortunately they do not help in my case. I created a very small test case that shows my issue. (the problem with calling Renderer java script function). The "edit" function call is working fine. Just to reiterate - same thing works fine in a standalone version. Please see below.

    Test.Master.cs
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    namespace LateralTransfer
    {
        public partial class Test1 : System.Web.UI.MasterPage
        {
            protected void Page_Load(object sender, EventArgs e)
            {
    
            }
        }
    }
    Test.Master
    <%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Test.master.cs" Inherits="LateralTransfer.Test1" %>
    
    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
            <div>
                <asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
                </asp:ContentPlaceHolder>
            </div>
        </form>
    </body>
    </html>

    TestMaster.aspx.cs
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using Ext.Net;
    using LateralTransfer.Data;
    
    namespace LateralTransfer
    {
        public partial class TestMaster : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                if (!X.IsAjaxRequest)
                {
                    this.BindData();
                }
    
            }
    
            private void BindData()
            {
                this.StoreCombo.DataSource = TransferStatus.GetAll();
                this.StoreCombo.DataBind();
    
                this.Store1.DataSource = GetDataNew();
                this.Store1.DataBind();
            }
    
            private List<Client> GetDataNew()
            {
                List<Client> clntList = new List<Client>();
    
                clntList.Add(new Client() { ID = 10, NameNew = "Client 1 Name", TransferStatus_ID = 1 });
                clntList.Add(new Client() { ID = 11, NameNew = "Client 2 Name", TransferStatus_ID = 7 });
    
                return clntList;
            }
    
            [DirectMethod(Namespace = "ClientX")]
            public void EditNew(int id, string field, string oldValue, string newValue, object customer)
            {
                string message = "<b>Property:</b> {0}<br /><b>Field:</b> {1}<br /><b>Old Value:</b> {2}<br /><b>New Value:</b> {3}";
    
                // Send Message...
                X.Msg.Notify(new NotificationConfig()
                {
                    Title = "Edit Record #" + id.ToString(),
                    Html = string.Format(message, id, field, oldValue, newValue),
                    Width = 250,
                    Height = 150
                }).Show();
    
                this.GridPanel1.GetStore().GetById(id).Commit();
            }
    
            public class TransferStatus
            {
                public int ID { get; set; }
                public string Name { get; set; }
    
                public static List<TransferStatus> GetAll()
                {
                    return new List<TransferStatus>
                           {
                               new TransferStatus {ID = 1, Name = "Pending"},
                               new TransferStatus {ID = 4, Name = "Accepted"},
                               new TransferStatus {ID = 7, Name = "Rejected"}
                           };
                }
            }
            public class Client
            {
                public int ID { get; set; }
                public string NameNew { get; set; }
                public int TransferStatus_ID { get; set; }
            }
        }
    }
    TestMaster.aspx
    <%@ Page Title="" Language="C#" MasterPageFile="~/Test.Master" AutoEventWireup="true" CodeBehind="TestMaster.aspx.cs" Inherits="LateralTransfer.TestMaster" %>
    
    <asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
        <script type="text/javascript">
            var template = 'color:{0};';
    
            var change = function (value, meta) {
                meta.style = Ext.String.format(template, (value > 0) ? "green" : "red");
                return value;
            };
    
            var pctChange = function (value, meta) {
                meta.style = Ext.String.format(template, (value > 0) ? "green" : "red");
                return value + "%";
            };
    
            var edit = function (editor, e) {
    
                if (!(e.value === e.originalValue || (Ext.isDate(e.value) && Ext.Date.isEqual(e.value, e.originalValue)))) {
                    ClientX.EditNew(e.record.data.ID, e.field, e.originalValue, e.value, e.record.data);
                }
            };
    
            var statusRenderer1 = function (value) {
                var r = App.StoreCombo.getById(value);
    
                if (Ext.isEmpty(r)) {
                    return "";
                }
    
                return r.data.Name;
            };
        </script>
    
            <ext:ResourceManager runat="server" />
    
            <ext:Store ID="StoreCombo" runat="server">
                <Model>
                    <ext:Model runat="server" IDProperty="ID">
                        <Fields>
                            <ext:ModelField Name="ID" />
                            <ext:ModelField Name="Name" />
                        </Fields>
                    </ext:Model>
                </Model>
            </ext:Store>
    
            <h1>Editable GridPanel With Save To [DirectMethod]</h1>
    
            <ext:GridPanel
                ID="GridPanel1"
                runat="server"
                Title="Editable GridPanel"
                Width="700"
                Height="250">
                <Store>
                    <ext:Store ID="Store1" runat="server">
                        <Model>
                            <ext:Model runat="server" IDProperty="ID">
                                <Fields>
                                    <ext:ModelField Name="ID" Type="Int" />
                                    <ext:ModelField Name="NameNew" />
                                    <ext:ModelField Name="TransferStatus_ID" Type="Int" />
                                </Fields>
                            </ext:Model>
                        </Model>
                    </ext:Store>
                </Store>
                <ColumnModel runat="server">
                    <Columns>
                        <ext:Column runat="server" Text="ID" DataIndex="ID" Width="35" Visible="false" />
                        <ext:Column runat="server" Text="Name New" DataIndex="NameNew" Flex="1">
                            <Editor>
                                <ext:TextField runat="server" />
                            </Editor>
                        </ext:Column>
                        <ext:Column runat="server" DataIndex="TransferStatus_ID" Text="Status Select" Width="200">
                            <Renderer Fn="statusRenderer1"></Renderer>
                            <Editor>
                                <ext:ComboBox ID="cbStatuses" StoreID="StoreCombo" DisplayField="Name" ValueField="ID" runat="server" />
                            </Editor>
                        </ext:Column>
                    </Columns>
                </ColumnModel>
                <SelectionModel>
                    <ext:CellSelectionModel runat="server" />
                </SelectionModel>
                <Plugins>
                    <ext:CellEditing runat="server">
                        <Listeners>
                            <Edit Fn="edit" />
                        </Listeners>
                    </ext:CellEditing>
                </Plugins>
            </ext:GridPanel>
    </asp:Content>
  7. #7
    Hello @Dennis!

    Thank you for the straightforward test case, I could reproduce the issue here!

    It seems I found just the topic where somebody else complained about the same issue: Data in the grid not getting populated when using Master Pages

    The problem is because, once you use a master page, every ID in the "slave page" gets prepended by its content placeholder id.

    So in your case, you won't have an App.StoreCombo at all, but rather an App.ContentPlaceHolder1_StoreCombo one.

    If you find that annoying to do the guesswork, you can rely on Ext.NET's ID expansion tokens. Of course, a plain <script /> tag won't expand those tokens, so for that, we have the ext:XScript control to implement this expansion in javascript code you may have. So, in the test sample you provided, you would move the statusRenderer1() definition out of the <script /> block, into an Ext.NET-governed block, like this:

    <ext:XScript runat="server">
        <script>
            var statusRenderer1 = function (value) {
                var r = #{StoreCombo}.getById(value);
    
                if (Ext.isEmpty(r)) {
                    return "";
                }
    
                return r.data.Name;
            };
        </script>
    </ext:XScript>
    And then your page should render just right no matter what content placeholder ID you give to the master-slave page setup.

    As I believe you may be relying in an external javascript file, then you should adjust the ID to reflect the content placeholder's ID from there.

    Yet another solution that would allow you to have the js code outside (in a dedicated javascript file) would involve actually passing the store to the statusRenderer1() renderer. So, the method would have to be changed to receive the reference to the store, like this:

    var statusRenderer1 = function (value, cbStore) {
        var r = cbStore.getById(value);
    
        if (Ext.isEmpty(r)) {
            return "";
        }
    
        return r.data.Name;
    };
    And now you won't be able to rely on renderer's Fn= property, but explore it via a small Handler= assignment, like this:

    <Renderer Handler="return statusRenderer1(value, #{StoreCombo});"></Renderer>
    Basically, you are moving the "token expansion" job where it is always available, so you won't need to do that in your javascript code at all. But you'll need to switch from simpler Fn to Handler as you want to go "custom", to pass something the handler won't guess it should.

    Hope this helps! There are other solutions possible to achieve the same; the above ones are just a few possibilities I could think of by now.
    Fabrício Murta
    Developer & Support Expert
  8. #8
    Fabricio - that worked. I used the ext:XScript block.

    Thank you!
  9. #9
    Glad it helped!

    Your test case really helped clear things up. Thanks for the feedback!
    Fabrício Murta
    Developer & Support Expert

Similar Threads

  1. Replies: 1
    Last Post: Jul 15, 2013, 1:35 PM
  2. Replies: 4
    Last Post: Feb 25, 2013, 9:23 AM
  3. Gridpanel undefined in Master page
    By gustavordgz in forum 1.x Help
    Replies: 2
    Last Post: Sep 08, 2010, 8:56 PM
  4. Replies: 2
    Last Post: May 05, 2010, 10:23 AM
  5. Master page issue Coolite + UpdatePanel
    By mthakershi in forum 1.x Help
    Replies: 4
    Last Post: Apr 03, 2008, 2:20 AM

Tags for this Thread

Posting Permissions