Strange behavior of paging when deleting record

  1. #1

    Strange behavior of paging when deleting record

    Hello

    there are two questions around the topic, probably having similar or same answer

    Example is mostly stolen from your examples, just littel modified, the key part of code is following:

      function simulateProblem() {
                var grid = Ext.getCmp('GridPanel1')
                GridPanel1.down('toolbar').moveLast()
                var f = function () {
                    for (var j = 21; j < 30; j++) {
                        var rec = grid.store.getAt(0);
                        grid.store.remove(rec);
                    }
                }
                // f() with immediate call it works fine
                Ext.defer(f, 1000);
            }

    as you can see I'm just deleting all records on page where I'm. I expect to see page with no records, having paging toolbar working
    Hovewer, what I get is empty page and I cannot get anwhere from here ( i.e paging toolbar stops working)

    When I do not do the defer, it works pretty nicelly ( toolbar automatically switch o previous page - that's briliant and even more then I expected. Why there is different behavior between calling remove in defer and directly?

    Full source code:
    <%@ Page Language="C#" %>
    
    <script runat="server">
       
    	[DirectMethod(RethrowException = true)]
    	public static object[] LoadData(string action, Dictionary<string, object> extraParams)
        {
                DateTime now = DateTime.Now;
    
                return new object[]
                {
                    new object[] { "3m Co", 71.72, 0.02, 0.03, now },
                    new object[] { "Alcoa Inc", 29.01, 0.42, 1.47, now },
                    new object[] { "Altria Group Inc", 83.81, 0.28, 0.34, now },
                    new object[] { "American Express Company", 52.55, 0.01, 0.02, now },
                    new object[] { "American International Group, Inc.", 64.13, 0.31, 0.49, now },
                    new object[] { "AT&T Inc.", 31.61, -0.48, -1.54, now },
                    new object[] { "Boeing Co.", 75.43, 0.53, 0.71, now },
                    new object[] { "Caterpillar Inc.", 67.27, 0.92, 1.39, now },
                    new object[] { "Citigroup, Inc.", 49.37, 0.02, 0.04, now },
                    new object[] { "E.I. du Pont de Nemours and Company", 40.48, 0.51, 1.28, now },
                    new object[] { "Exxon Mobil Corp", 68.1, -0.43, -0.64, now },
                    new object[] { "General Electric Company", 34.14, -0.08, -0.23, now },
                    new object[] { "General Motors Corporation", 30.27, 1.09, 3.74, now },
                    new object[] { "Hewlett-Packard Co.", 36.53, -0.03, -0.08, now },
                    new object[] { "Honeywell Intl Inc", 38.77, 0.05, 0.13, now },
                    new object[] { "Intel Corporation", 19.88, 0.31, 1.58, now },
                    new object[] { "International Business Machines", 81.41, 0.44, 0.54, now },
                    new object[] { "Johnson & Johnson", 64.72, 0.06, 0.09, now },
                    new object[] { "JP Morgan & Chase & Co", 45.73, 0.07, 0.15, now },
                    new object[] { "McDonald\"s Corporation", 36.76, 0.86, 2.40, now },
                    new object[] { "Merck & Co., Inc.", 40.96, 0.41, 1.01, now },
                    new object[] { "Microsoft Corporation", 25.84, 0.14, 0.54, now },
                    new object[] { "Pfizer Inc", 27.96, 0.4, 1.45, now },
                    new object[] { "The Coca-Cola Company", 45.07, 0.26, 0.58, now },
                    new object[] { "The Home Depot, Inc.", 34.64, 0.35, 1.02, now },
                    new object[] { "The Procter & Gamble Company", 61.91, 0.01, 0.02, now },
                    new object[] { "United Technologies Corporation", 63.26, 0.55, 0.88, now },
                    new object[] { "Verizon Communications", 35.57, 0.39, 1.11, now },
                    new object[] { "Wal-Mart Stores, Inc.", 45.45, 0.73, 1.63, now }
                };
        }
    </script>
    
    <!DOCTYPE html>
    
    <html>
    <head runat="server">
        <title>Simple Array Grid With Paging and Remote Reloading - Ext.NET Examples</title>
    
        <script>
            var template = '<span style="color:{0};">{1}</span>';
    
            var change = function (value) {
                return Ext.String.format(template, (value > 0) ? "green" : "red", value);
            };
    
            var pctChange = function (value) {
                return Ext.String.format(template, (value > 0) ? "green" : "red", value + "%");
            };
    
            function simulateProblem() {
                var grid = Ext.getCmp('GridPanel1')
                GridPanel1.down('toolbar').moveLast()
                var f = function () {
                    for (var j = 21; j < 30; j++) {
                        var rec = grid.store.getAt(0);
                        grid.store.remove(rec);
                    }
                }
                // f() with immediate call it works fine
                Ext.defer(f, 1000);
            }
        </script>
    
        <ext:XScript runat="server">
            <script type="text/javascript">
                var handlePageSizeSelect = function (item, records) {
                    var curPageSize = #{ GridPanel1 }.store.pageSize,
                        wantedPageSize = parseInt(item.getValue(), 10);
    
                    if (wantedPageSize != curPageSize) {
                        #{ GridPanel1 }.store.pageSize = wantedPageSize;
                        #{ GridPanel1 }.store.reload();
                    }
                }
            </script>
        </ext:XScript>
    </head>
    <body>
        <form runat="server">
            <ext:ResourceManager runat="server" Namespace="" />
    
    		<ext:Button runat="server" OnClientClick="simulateProblem()" Text="Simulate problem" ></ext:Button>
    
            <ext:GridPanel
                ID="GridPanel1"
                runat="server"
                Title="Array Grid"
                Width="800">
                <Store>
                    <ext:Store ID="Store1" runat="server"  AutoLoad="True" PageSize="10" RemoteSort="false" RemotePaging="false">
                        <Model>
                            <ext:Model runat="server">
                                <Fields>
                                    <ext:ModelField Name="company" />
                                    <ext:ModelField Name="price" Type="Float" />
                                    <ext:ModelField Name="change" Type="Float" />
                                    <ext:ModelField Name="pctChange" Type="Float" />
                                    <ext:ModelField Name="lastChange" Type="Date" />
                                </Fields>
                            </ext:Model>
                        </Model>
    	                <Proxy>
    		                <ext:PageProxy DirectFn="Ext.net.DirectMethods.LoadData">
    		                </ext:PageProxy>
    	                </Proxy>
                    </ext:Store>
                </Store>
                <ColumnModel runat="server">
                    <Columns>
                        <ext:RowNumbererColumn runat="server" Width="35" />
                        <ext:Column runat="server" Text="Company" DataIndex="company" Flex="1" />
                        <ext:Column runat="server" Text="Price" Width="75" DataIndex="price">
                            <Renderer Format="UsMoney" />
                        </ext:Column>
                        <ext:Column runat="server" Text="Change" Width="75" DataIndex="change">
                            <Renderer Fn="change" />
                        </ext:Column>
                        <ext:Column runat="server" Text="Change" Width="75" DataIndex="pctChange">
                            <Renderer Fn="pctChange" />
                        </ext:Column>
                        <ext:DateColumn runat="server" Text="Last Updated" Width="125" DataIndex="lastChange" Format="H:mm:ss" />
                    </Columns>
                </ColumnModel>
                <SelectionModel>
                    <ext:RowSelectionModel runat="server" Mode="Multi" />
                </SelectionModel>
                <View>
                    <ext:GridView runat="server" StripeRows="true" />
                </View>
                <BottomBar>
                     <ext:PagingToolbar runat="server">
                       
                    </ext:PagingToolbar>
                </BottomBar>
            </ext:GridPanel>
        </form>
    </body>
    </html>
  2. #2
    Hello, Jiri!

    Generally speaking, when you postpone a task, like with Ext.defer(), you give the app an opportunity window to trigger events before the deferred task runs. Javascript is not really parallel, so at least you have a deterministic effect; one when you do, and another when you don't defer the removal function execution.

    In this case, all I needed to do was to call once again the paging toolbar's moveLast() function, and the deferred method had the same behavior as if it was called at once.

    I did some tests like interrupting/resuming layouts/events with the grid, and couldn't isolate the exact events/layout updates that are being triggered; besides the grid panel itself, such interferences could be coming from the grid's view, the store itself, and even from another grid aspect (paging toolbar, selection model, to name a few).

    So, here's the updated version of the simulateProblem() function:

    function simulateProblem() {
        var grid = Ext.getCmp('GridPanel1')
        GridPanel1.down('toolbar').moveLast()
        var f = function () {
            for (var j = 21; j < 30; j++) {
                var rec = grid.store.getAt(0);
                grid.store.remove(rec);
            }
            GridPanel1.down('toolbar').moveLast();
        }
        Ext.defer(f, 1000);
    }
    (for clarity I simply copypasted the moveLast() command inside the deferred method, you could save a bit of DOM navigation overhead by saving the paging toolbar in a local variable or simply referring it directly)

    Is that an acceptable solution for your case, or do you have other constraints we should consider? I believe, if we get to the bottom of the issue, chances are, all we find is just alternatives to flicker or make look strange the view, for how long the delay may be to call the deferred function, as it's somewhat likely we'd need to hold on events or page changes to make it work exactly as if we don't delay the removal.

    Last, but not least, thanks for providing a test case we could reproduce your issue with, we hope it was worth your while!

    p.s.: sorry for the long delay posting back an answer, I had responded this early this week but perhaps some problem (with me?) prevented the message from being submitted; so much I could just walk back the browser history and recover the full text reply I'm pasting above.
    Fabrício Murta
    Developer & Support Expert
  3. #3
    OK

    just to be clear - we are facing this problem when we have (in browser paging) paged grid and user delete something on page 2 or later one, by clicking . That's where the "simulateProblem" function comes from ( i.e user open page 2, record by record delete everythign here and then is not redirected to previous page, but grid stays completelly "useless"

    So if I understand correctly, you are saying that to be sure grid stays working, we should call .moveLast() after each delete?

    If not clear what I mean I can create another sample

    Thanks
  4. #4
    Hello again, Jirihost!

    Quote Originally Posted by jirihost
    just to be clear - we are facing this problem when we have (in browser paging) paged grid and user delete something on page 2 or later one, by clicking . That's where the "simulateProblem" function comes from ( i.e user open page 2, record by record delete everythign here and then is not redirected to previous page, but grid stays completelly "useless"
    For this scenario, I believe this function could serve to illustrate it:

    function removeFirst() {
        var grid = Ext.getCmp('GridPanel1'),
            store = grid.getStore();
        var f = function () {
            store.remove(store.getAt(0));
        }
        Ext.defer(f, 1000);
    }
    Delete entries from the last page, looks right, until you delete the last one.
    Delete entries in 1st or 2nd page, it looks right, but you get less than 10 entries per page as you delete records. This works, but doesn't look right; it should bring entries from the next page as we know there are -- until exhausted.

    So simply change the function to load the current page over every single removal:

    function removeFirst() {
        var grid = Ext.getCmp('GridPanel1'),
            store = grid.getStore();
        var f = function () {
            store.remove(store.getAt(0));
            store.loadPage(store.currentPage);
        }
        Ext.defer(f, 1000);
    }
    And that's it! Should work no matter you have wrapped or not in a Ext.defer().

    Notwithstanding, to get rid of some flicker as it removes the entry, just suspend layouts during removal:

    function removeFirst() {
        var grid = Ext.getCmp('GridPanel1'),
            store = grid.getStore();
        var f = function () {
            grid.suspendLayouts();
            store.remove(store.getAt(0));
            store.loadPage(store.currentPage);
            grid.resumeLayouts();
        }
        Ext.defer(f, 1000);
    }
    If you want to batch remove entries, do suspend the layout updates; then perform how many removals needed; and only once load the current page + resume layout updates.

    function removeFirst() {
        var grid = Ext.getCmp('GridPanel1'),
            store = grid.getStore();
        var f = function () {
            grid.suspendLayouts();
            for (my_condition_here(i)) {
                store.remove(store.getAt(i));
            }
            store.loadPage(store.currentPage);
            grid.resumeLayouts();
        }
        Ext.defer(f, 1000);
    }
    Quote Originally Posted by jirihost
    So if I understand correctly, you are saying that to be sure grid stays working, we should call .moveLast() after each delete?
    It seems more appropriate to refresh the currently loaded page than moving to the first or last pages once a record is removed, right? If the current page ceases to exist, then it should go to the previous page (which it already handles if you call store.loadPage()). The moveLast() approach was simply congruent to your test case constraints.

    Quote Originally Posted by jirihost
    If not clear what I mean I can create another sample
    If my answer above still doesn't match what you need, perhaps a new sample would be best. So it's your take whether another test case is required or not.

    Hope this helps!
    Fabrício Murta
    Developer & Support Expert

Similar Threads

  1. Replies: 0
    Last Post: Jun 20, 2016, 11:35 AM
  2. [CLOSED] Numberfield / strange behavior
    By tMp in forum 3.x Legacy Premium Help
    Replies: 2
    Last Post: Sep 08, 2015, 4:51 PM
  3. Store filter strange behavior
    By Zdenek in forum 2.x Help
    Replies: 3
    Last Post: Oct 31, 2014, 12:13 PM
  4. Strange behavior after nuget
    By bovo13 in forum 2.x Help
    Replies: 7
    Last Post: Oct 17, 2013, 1:21 PM
  5. Deleting record from Grid is not working
    By latif in forum 1.x Help
    Replies: 1
    Last Post: Dec 25, 2009, 12:18 PM

Posting Permissions