[OPEN] [#1853] Store Filter with GridPanel Paging

  1. #1

    [OPEN] [#1853] Store Filter with GridPanel Paging

    There's something wrong with store filters and grid panel paging.
    Filters are applied only to the visible rows and not over the whole store data.

    Could you please fix my code?

    GridPanelFilterAndPaging.cshtml

    @page
    @model ExtCookbook.Pages.GridPanelFilterAndPagingModel
    @{
    }
    <ext-section target="Main">
        <ext-container region="Center" scrollable="true" paddingAsString="30 20 30 50">
            <content>
                <h1>GridPanel with filters and paging</h1>
                <ext-textField model="@Model.SearchBox" />
                <ext-gridPanel model="@Model.Grid" />
            </content>
        </ext-container>
    </ext-section>
    GridPanelFilterAndPaging.cshtml.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Ext.Net;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.RazorPages;
    
    namespace ExtCookbook.Pages
    {
        public class GridPanelFilterAndPagingModel : PageModel
        {
    
            public GridPanel Grid { get; set; }
            public List<object> GridData { get; set; }
            public TextField SearchBox { get; set; }
            public void OnGet()
            {
    
                var now = DateTime.Now.ToString("yyyy-MM-dd hh:mm:tt");
                GridData = new List<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 }
                };
    
                Grid = new GridPanel()
                {
                    Id = "myGrid",
                    Title = "myGrid",
                    Anchor = "100%",
                    Region = RegionType.Center,
                    Columns = new List<Column>
                    {
                        new Column() {  DataIndex = "Company", Text = "Company", Flex = 1}
                    },
                    Store = new Store
                    {
                        Id = "myGridStore",
                        ModelValue = new Model
                        {
                            Fields = new List<DataField>
                            {
                                new DataField() { Name = "Company", Type = DataFieldType.String }
                            }
                        },
                        Data = GridData,
                        Proxy = new MemoryProxy
                        {
                            EnablePaging = true
                        },
                        PageSize = 5,
                    },
                    Bbar = new PagingToolbar()
                };
    
                SearchBox = new TextField
                {
                    FieldLabel = "Search: ",
                    EmptyText = "Type 'Microsoft' here..."
                };
                SearchBox.Listeners.Change.Handler = @"App.myGrid.store.clearFilter();
                    var filters = [];
                         if(!!newValue){
                            filters.push(
                                new Ext.util.Filter({
                                    filterFn: function (item) {
                                        return (!!item.get('Company') && item.get('Company').toLowerCase().indexOf(newValue.toLowerCase()) > -1);
                                }
                            }));
                        };
                    App.myGrid.store.filter(filters);";
            }
        }
    }
    Thank you for any suggestion!
  2. #2
    Hello @Bbros!

    In fact by just filtering the store in a memory proxy, you are but filtering the current page.

    What about using the GridFilters Plug In just like this 5.x example?

    If that sounds feasible, here's the changes I made in the method body and usings:

    using Ext.Net.Core;
    
    (...)
    
    // Column defined somewhere else...
    var column = new Column()
    {
        Id = "CompanyColumn",
        DataIndex = "Company",
        Text = "Company",
        Flex = 1,
        CustomConfig = new JsObject()
    };
    
    // So we can add its 'filter' settings in GridFilters plugin syntax.
    column.CustomConfig.Add("filter", new JsObject("{ type: 'string' }", ParameterMode.Raw));
    
    Grid = new GridPanel()
    {
        Id = "myGrid",
        Title = "myGrid",
        Anchor = "100%",
        Region = RegionType.Center,
        Columns = new List<Column>
        {
            column
        },
        Store = new Store
        {
            Id = "myGridStore",
            // You use the memory proxy to paginate, so filter is "remote"
            // relative to the store.
            RemoteFilter = true,
            ModelValue = new Model
            {
                Fields = new List<DataField>
                {
                    new DataField() { Name = "Company", Type = DataFieldType.String }
                }
            },
            Data = GridData,
            Proxy = new MemoryProxy
            {
                EnablePaging = true
            },
            PageSize = 5,
        },
        // Enable GridFilters plugin. You can remove brackets initializer if you don't mind column context menu filters.
        Plugins = new GridFilters() { ShowMenu = false },
        Bbar = new PagingToolbar()
    };
    
    SearchBox = new TextField
    {
        FieldLabel = "Search: ",
        EmptyText = "Type 'Microsoft' here..."
    };
    
    // Much simpler client-side method to apply filters. If empty string means filter is clear.
    // This string filter is case insensitive.
    SearchBox.Listeners.Change.Handler = "App.CompanyColumn.filter.setValue(newValue)";
    
    // Just to avoid hammering the grid with filters in case there's a lot of records.
    SearchBox.Listeners.Change.Buffer = 1000;
    For brevety I shared only the part that changed, it replaces your model code's lines 54-100.

    And here's the literature on this filtering scheme if you're looking for its capabilities: Ext JS 7.3.1 docs: Ext.grid.filters.Filters.

    It is still possible to use the other filtering techniques, but the filters would need to be passed to the proxy instead. As the GridFilters plugin seemed a more feature-rich filtering technique, I felt it would be worth to develop the answer on top of it, as it would do the remote ceremonial for you and even add nice menus as well as support several out-of-the box filtering by data type.

    Hope this helps!
    Fabrício Murta
    Developer & Support Expert
  3. #3
    Always it helps! I was searching for that plugin and I was thinking that is not available anymore!
    Your point is good and easy for most cases, but I simplified a more complex scenario in order to make a repro project.

    I started to migrate some application from v5.3 to v7.x.
    In previous version setting Store.PageSize is all I need to have paging; in v7 this is not so.
    I don't want to use a MemoryProxy (I don't even know what is ;)), I think I just need it to make the paging work; if there are alternatives I'd like to use those.

    In my scenario a single "SearchBox" is able to filter over different columns (and this is working in v5).
    Here is new code (I'm sorry not to have posted before, but I'm happy for your solution).

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Ext.Net;
    using Microsoft.AspNetCore.Mvc.RazorPages;
    
    namespace ExtCookbook.Pages
    {
        public class GridPanelFilterAndPagingModel : PageModel
        {
    
            public GridPanel Grid { get; set; }
            public List<object> GridData { get; set; }
            public TextField SearchBox { get; set; }
            public void OnGet()
            {
    
                 GridData = new List<object>
                {
                    new object[] { "Cheesecake Factory", "American", "Lorem ipsum dolor sit amet", 1 },
                    new object[] { "University Cafe", "American", "Lorem ipsum dolor sit amet", 4 },
                    new object[] { "Slider Bar", "American", "Lorem ipsum dolor sit amet", 0 },
                    new object[] { "Pizzeria", "Italian", "Lorem ipsum dolor sit amet", 2 },
                    new object[] { "El Mariachi", "Mexican", "Lorem ipsum dolor sit amet", 3 },
                    new object[] { "El Loco", "Mexican", "Lorem ipsum dolor sit amet", 1 },
                    new object[] { "Ristorante", "Italian", "Lorem ipsum dolor sit amet", 1 },
                };
    
                Grid = new GridPanel()
                {
                    Id = "myGrid",
                    Title = "myGrid",
                    Anchor = "100%",
                    Region = RegionType.Center,
                    Columns = new List<Column>
                    {
                        new Column() {  DataIndex = "Company", Text = "Company", Flex = 1},
                        new Column() {  DataIndex = "Cuisine", Text = "Cuisine", Flex = 1},
                        new Column() {  DataIndex = "Desctiption", Text = "Desctiption", Flex = 1},
                        new Column() {  DataIndex = "Rating", Text = "Rating", Flex = 1},
                    },
                    Store = new Store
                    {
                        Id = "myGridStore",
                        ModelValue = new Model
                        {
                            Fields = new List<DataField>
                            {
                                new DataField() { Name = "Company", Type = DataFieldType.String },
                                new DataField() { Name = "Cuisine", Type = DataFieldType.String },
                                new DataField() { Name = "Desctiption", Type = DataFieldType.String },
                                new DataField() { Name = "Rating", Type = DataFieldType.Int }
                            }
                        },
                        Data = GridData,
                        Proxy = new MemoryProxy
                        {
                            EnablePaging = true
                        },
                        PageSize = 5,
                    },
                    Bbar = new PagingToolbar()
                };
    
                SearchBox = new TextField
                {
                    FieldLabel = "Search: ",
                    EmptyText = "Type 'ita' or 'el' here...",
                    Width = 350
                };
    
                var whereFields = new List<string>();
                foreach (DataField df in ((List<DataField>)((Model)((Store)Grid.Store).ModelValue).Fields).Where(x => x.Type == DataFieldType.String))
                {
                    whereFields.Add($"(!!item.get('{df.Name}') && item.get('{df.Name}').toLowerCase().indexOf(newValue.toLowerCase()) > -1)");
                }
    
                SearchBox.Listeners.Change.Handler = @"App.myGrid.store.clearFilter();
                    var filters = [];
                         if(!!newValue){
                            filters.push(
                                new Ext.util.Filter({
                                    filterFn: function (item) {
                                     return " + String.Join("||", whereFields) + @";
                                }
                            }));
                        };
                    App.myGrid.store.filter(filters);";
            }
        }
    }
    Thank you again!
  4. #4
    Hello @bbros!

    Quote Originally Posted by bbros
    I started to migrate some application from v5.3 to v7.x.
    In previous version setting Store.PageSize is all I need to have paging; in v7 this is not so.
    I don't want to use a MemoryProxy (I don't even know what is ;)), I think I just need it to make the paging work; if there are alternatives I'd like to use those.
    So... Do you have handy this test case, how would it look like if you were using Ext.NET 5, using the syntax you needed for it to work previous version?

    It is true that version 5 had neat syntax sugar that made somewhat complicated scenarios look simpler so you could develop with it for years without even knowing what a memory proxy is. But this also made some cross reference between Ext JS and Ext.NET harder, which the new version aims to eliminate (the overall syntax and API will be more concise between both sides).

    Well, then maybe if you have the version in v5 that works with it we could take it in consideration while providing a solution, in case something else that we may suggest escapes the constraints that the old version algorithm fulfilled.
    Fabrício Murta
    Developer & Support Expert
  5. #5
    Hello once again, @Bbros!

    And here's a more conservative attempt, using Ext.NET's implementation of paging store that fortunately went in Ext.NET 7 albeit not directly accessible via API:

    1. remove your memory proxy definitions as you defined in lines 56-59 from the model code you provided in the last post.
    2. add this custom config to set the store as Ext.NET's paging-aware store:

    CustomConfig = new JsObject() { { "type", "paging" } },
    If I'm not missing anything this should be all you need to make your example work fine with your custom filter; paging and all.

    Please let us know if I forgot anything or you still can't make your test case work with the directions given. If that's still a no-go for you for any other reason, the v5 test case might just help us provide you a solution that mimicks the overall environment given code generated by v5.

    As this is a missing feature/component from Ext.NET 7 that was not really an UX (covered by issue #1741), I have logged GitHub issue #1853 to track this missing feature. This feature is pretty related to the paging overall support but specific to the paging-aware store, already implemented client-side.

    Hope this helps!
    Fabrício Murta
    Developer & Support Expert
  6. #6
    Thank you very much.
    With
    CustomConfig = new JsObject() { { "type", "paging" } }
    it works as a charm.

    The equivalent code in v5 is which follows (WebForms and VB.NET)

    <%@ Page Language="vb" AutoEventWireup="false" CodeBehind="GridPagingWithSearchBox.aspx.vb" Inherits="BBros.ExtCookbook.GridPagingWithSearchBox" %>
    
    <!DOCTYPE html>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title></title>
        <script>
            var search = function (field, newValue) {
                App.myGrid.store.clearFilter();
                var searchValue = App.txtSearch.value;
                var filters = [];
                if (!!searchValue) {
                    filters.push(
                        new Ext.util.Filter({
                            filterFn: function (item) {
                                return (!!item.get('Company') && item.get('Company').toLowerCase().indexOf(searchValue.toLowerCase()) > -1)
                                    || (!!item.get('Cuisine') && item.get('Cuisine').toLowerCase().indexOf(searchValue.toLowerCase()) > -1);
                            }
                        }));
                }
                App.myGrid.store.filter(filters);
            };
        </script>
        <script runat="server">
    
            Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
                Dim rm As New ResourceManager
                Me.form1.Controls.Add(rm)
                Dim txtSearch As New Ext.Net.TextField With {.ID = "txtSearch", .Width = 270, .Icon = Icon.Magnifier, .EmptyText = "search here"}
                txtSearch.Listeners.Change.Handler = "search(this, newValue);"
                Me.form1.Controls.Add(txtSearch)
                Me.form1.Controls.Add(GetGridPanel())
            End Sub
    
            Private Function GetGridPanel() As GridPanel
                Dim m As New Model
                m.Fields.Add("Company", ModelFieldType.String)
                m.Fields.Add("Cuisine", ModelFieldType.String)
    
                Dim s As New Store
                s.ID = "MyStore"
                s.PageSize = 5
                s.Model.Add(m)
    
    
                Dim GridData = New List(Of Object) From
               {
                    New With {.Company = "Cheesecake Factory", .Cuisine = "American", .Description = "Lorem ipsum dolor sit amet", .Rating = 1},
                    New With {.Company = "University Cafe", .Cuisine = "American", .Description = "Lorem ipsum dolor sit amet", .Rating = 4},
                    New With {.Company = "Slider Bar", .Cuisine = "American", .Description = "Lorem ipsum dolor sit amet", .Rating = 0},
                    New With {.Company = "Pizzeria", .Cuisine = "Italian", .Description = "Lorem ipsum dolor sit amet", .Rating = 2},
                    New With {.Company = "El Mariachi", .Cuisine = "Mexican", .Description = "Lorem ipsum dolor sit amet", .Rating = 3},
                    New With {.Company = "El Loco", .Cuisine = "Mexican", .Description = "Lorem ipsum dolor sit amet", .Rating = 1},
                    New With {.Company = "Ristorante", .Cuisine = "Italian", .Description = "Lorem ipsum dolor sit amet", .Rating = 1}
                }
    
                s.Data = GridData
    
                Dim grd As New GridPanel With {
                    .ID = "myGrid",
                    .Width = 300,
                    .Header = 200,
                    .Title = "myGrid"}
    
                grd.ColumnModel.Columns.Add(New Column With {.DataIndex = "Company", .Text = "Company"})
                grd.ColumnModel.Columns.Add(New Column With {.DataIndex = "Cuisine", .Text = "Cuisine"})
                grd.Store.Add(s)
    
                grd.BottomBar.Add(New PagingToolbar With {.DisplayInfo = True,
                                                   .DisplayMsg = "Page",
                                                   .HideRefresh = True,
                                                   .InputItemWidth = 30})
                Return grd
            End Function
    
        </script>
    </head>
    <body>
        <form id="form1" runat="server">
            <div>
            </div>
        </form>
    </body>
    </html>
  7. #7
    Hello again, Bbros!

    Glad it works, and thanks for the test case, it really elucidates how you didn't need to know about what happened under the hood when you included a paging toolbar. In fact, in v5 and before, once you instantiate a paging toolbar, it will look for the associated store and "mark" it as a paging store for you just as we did here.

    The test case you provided helped ensure the last solution is more consistent with the code you are porting to the new version, I believe you should be good with the solution for the long run.

    Interesting project you have in hands, not only porting from legacy Ext.NET to Ext.NET 7 and the inherent .NET Framework/4 to .NET 5 (formerly .NET Core) but also from VB.NET to C#!
    Last edited by fabricio.murta; Feb 25, 2021 at 6:56 PM. Reason: There's no reason to mark this thread as closed, it is an issue and will only be closed once the issue/feature is implemented. :)

Similar Threads

  1. GridPanel paging is removing filter
    By mhd in forum 2.x Help
    Replies: 8
    Last Post: Jul 31, 2014, 2:47 PM
  2. [CLOSED] GridPanel JavaScript Filter with Paging Problem
    By Django in forum 2.x Legacy Premium Help
    Replies: 4
    Last Post: Jan 24, 2014, 12:21 PM
  3. [OPEN] [#328] Issue with Store Filter and group StartCollapsed=true
    By amitpareek in forum 2.x Legacy Premium Help
    Replies: 8
    Last Post: Aug 27, 2013, 4:55 AM
  4. Gridpanel Paging and Filter Problem.
    By Ganesh3.shirsath in forum 1.x Help
    Replies: 0
    Last Post: Feb 15, 2011, 7:16 AM
  5. Filter vs. GridPanel Paging
    By reiben in forum 1.x Help
    Replies: 3
    Last Post: Dec 09, 2010, 6:07 PM

Posting Permissions