ListFilter with mappings

  1. #1

    ListFilter with mappings

    Hi,
    In Ext.Js the ListFilter has the option to pass Key-Value Pairs (Array with two elements) or an Js object with id/name properties.

    How can I access that functionality through Ext.Net? I need it because my grid has enum columns where the values in the store are integers and I render them as localized strings through a column formatter. Therefore the filter should display the localized strings but use the underlying numeric enum values for filtering.

    Thanks for any hints.
  2. #2
    Hi,

    As far as I can know there is no ListFilter in pure ExtJS.

    I guess you are telling about some plugin. What is the name of plugin? I'm pretty sure this is GridFilters. If so, there is all GridFilters functionality in Ext.Net.

    So, could you provide a sample to reproduce the problem?
  3. #3
    Yes I'm talking about the grid filters (which are already in Ext.Net), but I thought it is part of Ext.Js because it is included in their download. If all the functionality is already in Ext.Net I'm just asking how to access it :-)

    When I download the source zip for Ext.Js 3.3.0 I can find ListFilter.js at path "ext-3.3.0\examples\ux\gridfilters\filter\ListFilter.js "

    When I open the file in a text editor it has documentation and says (pretty much at the top of the file, note that there are 3 different possible formats for the options array):

        /**
         * @cfg {Array} options
         * <p><code>data</code> to be used to implicitly create a data store
         * to back this list when the data source is <b>local</b>. If the
         * data for the list is remote, use the <code>{@link #store}</code>
         * config instead.</p>
         * <br><p>Each item within the provided array may be in one of the
         * following formats:</p>
         * <div class="mdetail-params"><ul>
         * <li><b>Array</b> :
         * <pre><code>
    options: [
        [11, 'extra small'], 
        [18, 'small'],
        [22, 'medium'],
        [35, 'large'],
        [44, 'extra large']
    ]
         * </code></pre>
         * </li>
         * <li><b>Object</b> :
         * <pre><code>
    labelField: 'name', // override default of 'text'
    options: [
        {id: 11, name:'extra small'}, 
        {id: 18, name:'small'}, 
        {id: 22, name:'medium'}, 
        {id: 35, name:'large'}, 
        {id: 44, name:'extra large'} 
    ]
         * </code></pre>
         * </li>
         * <li><b>String</b> :
         * <pre><code>
         * options: ['extra small', 'small', 'medium', 'large', 'extra large']
         * </code></pre>
         * </li>
         */
  4. #4
    Hi,

    Well, when it deals with JS it will look the same in Ext.Net. I mean if ListFilter is created via JS.

    Regarding the markup (code behind).

    The third way looks just:
    <ext:ListFilter DataIndex="test1" Options="test11, test12, test13" />
    The second way can look like this:
    <ext:ListFilter DataIndex="test" StoreID="Store1" LabelField="test" />
    http://forums.ext.net/showthread.php...ll=1#post38965

    But I have discovered a problem with the example from this thread. It doesn't work with the latest code. We are working on the fix.

    Could you test this example using Ext.Net RC1?
  5. #5
    Quote Originally Posted by Daniil View Post
    Regarding the markup (code behind).

    The third way looks just:
    <ext:ListFilter DataIndex="test1" Options="test11, test12, test13" />
    Yes I understand that, but that doesn't work in my case, because the column values in the store are different from the displayed column values. I need the first or second way from the documentation I posted, because the store content doesn't match what is displayed.

    Quote Originally Posted by Daniil View Post
    The second way can look like this:
    <ext:ListFilter DataIndex="test" StoreID="Store1" LabelField="test" />
    http://forums.ext.net/showthread.php...ll=1#post38965

    But I have discovered a problem with the example from this thread. It doesn't work with the latest code. We are working on the fix.

    Could you test this example using Ext.Net RC1?
    I've tested the linked example. It seems to work in RC1 except that filter items get removed after checking them. In any way it is not what I need. It builds the list of filters from the store, but that means in my case I end up with a list of numbers.


    Here's an example of what I want to do (code-behind is empty):
    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="GridTest._Default" %>
    <%@ Register TagPrefix="ext" Namespace="Ext.Net" Assembly="Ext.Net" %>
    <%@ Import Namespace="System.Linq" %>
    <%@ Import Namespace="System.Collections.Generic" %>
    <%@ Import Namespace="Ext.Net" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form runat="server" id="wForm">
        <div>
            <ext:ResourceManager runat="server" ID="wResMgr" />
            <ext:GridPanel runat="server" ID="wGrid" Width="600" Height="400">
                <Store>
                    <ext:Store runat="server" ID="wStore" OnRefreshData="wStore_Refresh">
                        <Reader>
                            <ext:ArrayReader>
                                <Fields>
                                    <ext:RecordField Name="key" Type="String" />
                                    <ext:RecordField Name="value" Type="Int" />
                                </Fields>
                            </ext:ArrayReader>
                        </Reader>
                    </ext:Store>
                </Store>
                <ColumnModel runat="server" ID="wColumns">
                    <Columns>
                        <ext:Column Header="Line" DataIndex="key" />
                        <ext:Column Header="Value" DataIndex="value">
                            <Renderer Handler="function(v){return {0:'empty',1:'value 1',2:'value 2'}[v];}" />
                        </ext:Column>
                    </Columns>
                </ColumnModel>
                <Plugins>
                    <ext:GridFilters runat="server" ID="wFilter" />
                </Plugins>
            </ext:GridPanel>
        </div>
        </form>
    </body>
    </html>
    
    <script runat="server">
        
        protected void Page_Load(object sender, EventArgs e)
        {
            ListFilter filter = new ListFilter();
            filter.DataIndex = "value";
            filter.Options = new string[] { "empty", "value 1", "value 2" }; // this does not work
            wFilter.Filters.Add(filter);
    
            if (!X.IsAjaxRequest)
            {
                wStore.DataSource = this.Data.ToArray();
                wStore.DataBind();
            }
        }
    
        protected void wStore_Refresh(object sender, StoreRefreshDataEventArgs e)
        {
            IEnumerable<object[]> data = this.Data;
            
            string rawFilter = e.Parameters["filter"];
            if(!string.IsNullOrEmpty(rawFilter))
            {
                var filter = new FilterConditions(rawFilter);
                foreach (var cond in filter.Conditions)
                {
                    if (cond.FilterType != FilterType.List || cond.Comparison != Comparison.Eq || cond.Name != "value")
                        throw new NotImplementedException();
                    
                    // doesn't work because we get passed the text values and not the column values we wanted to filter
                    var filterValues = cond.ValuesList;
                    data = data.Where(obj => filterValues.Contains(obj[1].ToString()));
                }
            }
    
            wStore.DataSource = data.ToArray();
        }
        
        private IEnumerable<object[]> Data
        {
            get
            {
                for (int i = 0; i < 100; i++)
                    yield return new object[] { "line" + i, i % 3 };
            }
        }
        
    </script>
    When I examine the generated javascript from the browser I find following snippet:
    new Ext.ux.grid.GridFilters({
      filters: [{
      dataIndex: "value",
      type: "list",
      options: ["empty","value 1","value 2"]
    }]
    })
    What I need is to specify a mapping, if you look at the documentation of ListFilter.js I posted above you are supposed to do a mapping this way:
    new Ext.ux.grid.GridFilters({
      filters: [{
      dataIndex: "value",
      type: "list",
      options: [[0,"empty"],[1,"value 1"],[2,"value 2"]]
    }]
    })
    How do I get Ext.Net do generate such a mapping?
    Last edited by syncos; Dec 10, 2010 at 10:07 AM.
  6. #6
    Quote Originally Posted by syncos View Post
    I've tested the linked example. It seems to work in RC1 except that filter items get removed after checking them. In any way it is not what I need.
    For others how may be interested. The following example demonstrates how to use StoreID of ListFilter.

    Example
    <%@ Page Language="C#" %>
    
    <%@ Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>
    
    <script runat="server">
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!X.IsAjaxRequest)
            {
                Store store = this.GridPanel1.GetStore();
                store.DataSource = new object[] 
                { 
                    new object[] {"test11", "test12", "test13"},
                    new object[] {"test12", "test22", "test23"},
                    new object[] {"test13", "test32", "test33"}
                };
                store.DataBind();
    
                this.StoreOptions.DataSource = new object[] 
                { 
                    new object[] { "test12" },
                    new object[] { "test22" },
                    new object[] { "test32" }
                };
                this.StoreOptions.DataBind();
            }
        }
    </script>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title>Ext.Net Example</title>
    </head>
    <body>
        <form runat="server">
        <ext:ResourceManager runat="server" />
        <ext:Store ID="StoreOptions" runat="server">
            <Reader>
                <ext:ArrayReader IDProperty="test2">
                    <Fields>
                        <ext:RecordField Name="test2" />
                    </Fields>
                </ext:ArrayReader>
            </Reader>
        </ext:Store>
        <ext:GridPanel ID="GridPanel1" runat="server" AutoHeight="true">
            <Store>
                <ext:Store runat="server">
                    <Reader>
                        <ext:ArrayReader>
                            <Fields>
                                <ext:RecordField Name="test1" />
                                <ext:RecordField Name="test2" />
                                <ext:RecordField Name="test3" />
                            </Fields>
                        </ext:ArrayReader>
                    </Reader>
                </ext:Store>
            </Store>
            <ColumnModel runat="server">
                <Columns>
                    <ext:Column Header="Test1" DataIndex="test1" />
                    <ext:Column Header="Test2" DataIndex="test2" />
                    <ext:Column Header="Test3" DataIndex="test3" />
                </Columns>
            </ColumnModel>
            <Plugins>
                <ext:GridFilters>
                    <Filters>
                        <ext:ListFilter DataIndex="test1" Options="test11, test12, test13" />
                        <ext:ListFilter DataIndex="test2" StoreID="StoreOptions" LabelField="test2" />
                    </Filters>
                </ext:GridFilters>
            </Plugins>
        </ext:GridPanel>
        </form>
    </body>
    </html>
    Last edited by Daniil; Dec 11, 2010 at 8:45 AM. Reason: Minor correction
  7. #7
    Quote Originally Posted by syncos View Post
    I need the first or second way from the documentation I posted, because the store content doesn't match what is displayed.
    In any way it is not what I need. It builds the list of filters from the store, but that means in my case I end up with a list of numbers
    Here's an example of what I want to do (code-behind is empty):
    How do I get Ext.Net do generate such a mapping?
    Well, there is no way to get the first or second ways via markup or code-behind. Repeat myself, it can be done via JavaScript.

    But StoreID is what you really need:) I will demonstrate it further.

    Firstly, I should say - there are two mistakes in the code you provided.

    1. You expect remote filtering, but there is local filtering, it means there is no request to server. If there is no proxy OnRefreshData doesn't make sense. In my example below I used PageProxy as the simplest way to demonstrate.

    2. The following code
    string rawFilter = e.Parameters["filter"];
    must look as
    string rawFilter = e.Parameters["gridfilters"];
    Here is a result of combining the above.

    Example
    <%@ Page Language="C#" %>
    
    <%@ Register TagPrefix="ext" Namespace="Ext.Net" Assembly="Ext.Net" %>
    <%@ Import Namespace="System.Linq" %>
    <%@ Import Namespace="System.Collections.Generic" %>
    <%@ Import Namespace="Ext.Net" %>
    
    <script runat="server">
         
        protected void Page_Load(object sender, EventArgs e)
        {
            ListFilter filter = new ListFilter();
            filter.DataIndex = "value";
            filter.StoreID = "StoreOptions";
            filter.LabelField = "value";
            this.GridFilters1.Filters.Add(filter);
            if (!X.IsAjaxRequest)
            {
                this.GridPanel1.GetStore().DataSource = this.Data.ToArray();
                this.GridPanel1.GetStore().DataBind();
    
                this.StoreOptions.DataSource = new object[]
                {
                    new object[] { 0, "empty" },
                    new object[] { 1, "value 1" },
                    new object[] { 2, "value 2" }
                };
                this.StoreOptions.DataBind();
            }
        }
    
        protected void Store_OnRefreshData(object sender, StoreRefreshDataEventArgs e)
        {
            IEnumerable<object[]> data = this.Data;
    
            string rawFilter = e.Parameters["gridfilters"];
            if (!string.IsNullOrEmpty(rawFilter))
            {
                var filter = new FilterConditions(rawFilter);
                foreach (var cond in filter.Conditions)
                {
                    if (cond.FilterType != FilterType.List || cond.Comparison != Comparison.Eq || cond.Name != "value")
                        throw new NotImplementedException();
    
                    var filterValues = cond.ValuesList;
                    data = data.Where(obj => filterValues.Contains(obj[1].ToString()));
                }
            }
    
            this.GridPanel1.GetStore().DataSource = data.ToArray();
        }
    
        private IEnumerable<object[]> Data
        {
            get
            {
                for (int i = 0; i < 100; i++)
                    yield return new object[] { "line" + i, i % 3 };
            }
        }
         
    </script>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title>Ext.Net Example</title>
    </head>
    <body>
        <form runat="server">
        <ext:ResourceManager runat="server" />
        <ext:Store ID="StoreOptions" runat="server">
            <Reader>
                <ext:ArrayReader IDProperty="id">
                    <Fields>
                        <ext:RecordField Name="id" />
                        <ext:RecordField Name="value" />
                    </Fields>
                </ext:ArrayReader>
            </Reader>
        </ext:Store>
        <ext:GridPanel 
            ID="GridPanel1" 
            runat="server" 
            Height="400" 
            Width="400">
            <Store>
                <ext:Store runat="server" OnRefreshData="Store_OnRefreshData">
                    <Proxy>
                        <ext:PageProxy />
                    </Proxy>
                    <Reader>
                        <ext:ArrayReader>
                            <Fields>
                                <ext:RecordField Name="key" Type="String" />
                                <ext:RecordField Name="value" Type="Int" />
                            </Fields>
                        </ext:ArrayReader>
                    </Reader>
                </ext:Store>
            </Store>
            <ColumnModel runat="server">
                <Columns>
                    <ext:Column Header="Line" DataIndex="key" />
                    <ext:Column Header="Value" DataIndex="value">
                        <Renderer Handler="function(v){return {0:'empty',1:'value 1',2:'value 2'}[v];}" />
                    </ext:Column>
                </Columns>
            </ColumnModel>
            <Plugins>
                <ext:GridFilters ID="GridFilters1" runat="server" />
            </Plugins>
        </ext:GridPanel>
        </form>
    </body>
    </html>
    See also
    https://examples1.ext.net/#/GridPane...ilters_Remote/
  8. #8
    Quote Originally Posted by Daniil View Post
    Firstly, I should say - there are two mistakes in the code you provided.

    1. You expect remote filtering, but there is local filtering, it means there is no request to server. If there is no proxy OnRefreshData doesn't make sense. In my example below I used PageProxy as the simplest way to demonstrate.

    2. The following code
    string rawFilter = e.Parameters["filter"];
    must look as
    string rawFilter = e.Parameters["gridfilters"];
    Oops, my mistake. I made up the example from a larger project I'm working on, there I use a HttpProxy and set paramprefix="filter". I should have done more testing on the example, sorry. The changes you made fixed my mistakes.

    Quote Originally Posted by Daniil View Post
    Well, there is no way to get the first or second ways via markup or code-behind. Repeat myself, it can be done via JavaScript.

    But StoreID is what you really need :)
    Thanks, this worked! I wasn't aware that the store for the ListFilter can have both an id and a label column.

    Still it's a bit awkward because in the actual project I'm building my grid from dynamic data where I don't know in advance how many of such columns I need, so I may have to create stores dynamically.

    Maybe consider adding support for way 1 or 2 in the future?

    I tried doing it myself by subclassing ListFilter but I failed because OptionsProxy is not virtual:
    public class MappedListFilter : ListFilter
    {
        [TypeConverter(typeof(StringArrayConverter))]
        [DefaultValue(null)]
        [Description("The list of option ids")]
        public virtual string[] OptionIDs
        {
            get { return (string[])this.ViewState["OptionIDs"]; }
            set { this.ViewState["OptionIDs"] = value; }
        }
    
        [ConfigOption("options", JsonMode.Raw)]
        [DefaultValue("")]
        protected override string OptionsProxy // doesn't compile because not virtual in base class
        {
            get
            {
                string[] optionIDs = this.OptionIDs;
                string[] options = this.Options;
                if (string.IsNullOrEmpty(this.StoreID)
                    && optionIDs != null && optionIDs.Length > 0
                    && options != null && options.Length > 0)
                {
                    StringBuilder mapping = new StringBuilder();
                    mapping.Append('[');
                    for (int i = 0; i < optionIDs.Length && i < options.Length; i++)
                    {
                        if (i != 0)
                            mapping.Append(',');
                        mapping.Append('[');
                        mapping.Append(JSON.Serialize(optionIDs[i]));
                        mapping.Append(',');
                        mapping.Append(JSON.Serialize(options[i]));
                        mapping.Append(']');
                    }
                    mapping.Append(']');
                    return mapping.ToString();
                }
    
                return base.OptionsProxy;
            }
        }
    }
    Anyways, I'm going to turn to the StoreID solution for now.
    Last edited by syncos; Dec 13, 2010 at 8:58 AM.
  9. #9
    Quote Originally Posted by syncos View Post
    Maybe consider adding support for way 1 or 2 in the future?
    I tried doing it myself by subclassing ListFilter but I failed because OptionsProxy is not virtual
    This is out of my competence.

    You could add a respective feature request to
    http://forums.ext.net/forumdisplay.p...ature-Requests

Similar Threads

  1. [CLOSED] Scrolling ListFilter
    By cwolcott in forum 2.x Legacy Premium Help
    Replies: 6
    Last Post: Sep 05, 2012, 6:07 PM
  2. [CLOSED] ListFilter scroll bar?
    By vadym.f in forum 1.x Legacy Premium Help
    Replies: 2
    Last Post: Jul 05, 2012, 5:53 PM
  3. [CLOSED] ListFilter problem
    By vadym.f in forum 1.x Legacy Premium Help
    Replies: 2
    Last Post: Jun 12, 2012, 12:51 PM
  4. [CLOSED] ListFilter with a StoreID
    By SFritsche in forum 1.x Legacy Premium Help
    Replies: 14
    Last Post: Oct 08, 2010, 1:51 PM

Tags for this Thread

Posting Permissions