[CLOSED] DateFilter event listeners

  1. #1

    [CLOSED] DateFilter event listeners

    Hi,

    In our project, we make use of various types of filter plugins handling their client side events. From my observation, the DateFilter has a different behavior in the sense that its Update event fires even when either Activate or Deactivate event occurs. First, Activate or Deactivate event fires followed by Update. Other filter types like ListFilter or StringFilter behave as expected. Could you recommend an approach to suppress a redundant Update event for DateFilters? Please advise if more info is required.
    Last edited by Daniil; Apr 25, 2013 at 3:30 PM. Reason: [CLOSED]
  2. #2
    Hi Vadym,

    Could you, please, provide a test case to start with?
  3. #3
    Hi Daniil,

    Here're the steps to reproduce:

    1. Type in some text in the "Job Name" filter
    2. Observe that Activated event fires once on the first character input
    3. Continue typing and observe that Update event fires correctly
    4. Select the "Before" filter of the "Start" column
    5. Observe that Acivate event fires followed by Update in rapid succession
    6. Uncheck the "Before" filter and observe the Update and Deactivate events firing in rapid succession
    7. Expand the "Start" filter and select some date from the Date Picker directly
    8. Observe that Activate event is followed by Update event firing twice this time around


    Edit in: Suspending/resuming events within the Deactivate handler didn't seem to make a difference.

    <%@ Page Language="C#" %>
    
    <%@ Import Namespace="System.Collections.Generic" %>
    <%@ Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>
    <script runat="server">
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!ExtNet.IsAjaxRequest)
            {
                this.Store1.DataSource = this.Jobs;
                this.Store1.DataBind();
    
                //var sortInfo = new Ext.Net.SortInfo { Field = "Name", Direction = Ext.Net.SortDirection.DESC };
                //GridPanel1.GetStore().Sort(sortInfo.Field, sortInfo.Direction);
            }
        }
        private List<Job> Jobs
        {
            get
            {
                List<Job> jobs = new List<Job>();
                for (int i = 1; i <= 50; i++)
                {
                    jobs.Add(new Job(
                                i,
                                "Task" + i.ToString(),
                                DateTime.Today.AddDays(i),
                                DateTime.Today.AddDays(i + i),
                                (i % 3 == 0)));
                }
                return jobs;
            }
        }
        public class Job
        {
            public Job(int id, string name, DateTime start, DateTime end, bool completed)
            {
                this.ID = id;
                this.Name = name;
                this.Start = start;
                this.End = end;
                this.Completed = completed;
            }
            public int ID { get; set; }
            public string Name { get; set; }
            public DateTime Start { get; set; }
            public DateTime End { get; set; }
            public bool Completed { get; set; }
        }
    
        protected void Store1_DataBound(object sender, EventArgs e)
        {
            var store = sender as Store;
            if (store == null) return;
            var dataSource = store.DataSource;
            if (dataSource != null) return;
            this.Store1.DataSource = this.Jobs;
            this.Store1.DataBind();
        }
    </script>
    <!DOCTYPE html>
    <html>
    <head id="Head1" runat="server">
        <title></title>
        <ext:ResourcePlaceHolder ID="ResourcePlaceHolder1" runat="server" Mode="Script" />
        <ext:ResourcePlaceHolder ID="ResourcePlaceHolder2" runat="server" Mode="Style" />
        <script type="text/javascript" language="javascript">
            var onActivateFilter = function (filter, options) {
                alert("Activated!");
            };
    
            var onUpdateFilter = function (filter, options) {
                alert("Updated!");
            };
    
            var onDeactivateFilter = function (filter, options) {
                switch (filter.type) {
                    case "boolean":
                        break;
                    case "date":
                        filter.menu.items.each(function (item) {
                            if (item instanceof Ext.menu.CheckItem)
                                item.setChecked(false);
                        });
                        break;
                    case "list":
                        filter.menu.items.each(function (item) {
                            item.setChecked(false);
                        });
                        break;
                    case "numeric":
                        break;
                    case "string":
                        filter.menu.items.each(function (item) {
                            item.setValue("");
                        });
                        break;
                };
                alert("Deactivated!");
            };
        </script>
    </head>
    <body>
        <form id="form1" runat="server">
        <ext:ResourceManager ID="ResourceManager1" runat="server" />
        <ext:Viewport ID="ViewPort1" runat="server" Layout="BorderLayout">
            <Items>
                <ext:GridPanel ID="GridPanel1" runat="server" StripeRows="true" Height="320" MinHeight="160"
                    Region="North" CollapseMode="Mini" Split="true" SelectionMemory="Enabled">
                    <Store>
                        <ext:Store ID="Store1" runat="server" OnDataBinding="Store1_DataBound" AutoLoad="false"
                            WarningOnDirty="false">
                            <Reader>
                                <ext:JsonReader IDProperty="ID">
                                    <Fields>
                                        <ext:RecordField Name="ID" />
                                        <ext:RecordField Name="Name" />
                                        <ext:RecordField Name="Start" Type="Date" />
                                        <ext:RecordField Name="End" Type="Date" />
                                        <ext:RecordField Name="Completed" Type="Boolean" />
                                    </Fields>
                                </ext:JsonReader>
                            </Reader>
                        </ext:Store>
                    </Store>
                    <LoadMask ShowMask="false" />
                    <ColumnModel ID="ColumnModel1" runat="server">
                        <Columns>
                            <ext:Column ColumnID="ID" Header="ID" Width="40" DataIndex="ID" Hideable="false" />
                            <ext:Column ColumnID="Name" Width="160" Header="Job Name" DataIndex="Name" Hideable="true" />
                            <ext:DateColumn ColumnID="Start" Header="Start" Width="120" DataIndex="Start" Format="yyyy-MM-dd" />
                            <ext:DateColumn ColumnID="End" Header="End" Width="120" DataIndex="End" Format="yyyy-MM-dd" />
                            <ext:Column ColumnID="Completed" Header="Completed" Width="80" DataIndex="Completed">
                                <Renderer Handler="return (value) ? 'Yes':'No';" />
                            </ext:Column>
                        </Columns>
                    </ColumnModel>
                    <SelectionModel>
                        <ext:RowSelectionModel runat="server" SingleSelect="true" ID="RowSelectionModel1" />
                    </SelectionModel>
                    <LoadMask ShowMask="true" />
                    <BottomBar>
                        <ext:PagingToolbar ID="PagingToolbar1" runat="server" PageSize="10" DisplayInfo="true"
                            DisplayMsg="Displaying Jobs {0} - {1} of {2}">
                            <Items>
                            </Items>
                        </ext:PagingToolbar>
                    </BottomBar>
                    <View>
                        <ext:GridView ID="GridView1" runat="server">
                        </ext:GridView>
                    </View>
                    <Plugins>
                        <ext:GridFilters runat="server" ID="GridFilters1" Local="true">
                            <Filters>
                                <ext:DateFilter DataIndex="Start">
                                    <DatePickerOptions runat="server" TodayText="Now" />
                                    <Listeners>
                                        <Deactivate Fn="onDeactivateFilter" />
                                        <Activate Fn="onActivateFilter" />
                                        <Update Fn="onUpdateFilter" />
                                    </Listeners>
                                </ext:DateFilter>
                                <ext:DateFilter DataIndex="End">
                                    <DatePickerOptions runat="server" TodayText="Now" />
                                    <Listeners>
                                        <Deactivate Fn="onDeactivateFilter" />
                                        <Activate Fn="onActivateFilter" />
                                        <Update Fn="onUpdateFilter" />
                                    </Listeners>
                                </ext:DateFilter>
                                <ext:StringFilter DataIndex="Name" EmptyText="Type in...">
                                    <Listeners>
                                        <Deactivate Fn="onDeactivateFilter" />
                                        <Activate Fn="onActivateFilter" />
                                        <Update Fn="onUpdateFilter" />
                                    </Listeners>
                                </ext:StringFilter>
                            </Filters>
                        </ext:GridFilters>
                    </Plugins>
                    <Listeners>
                        <ViewReady Handler="this.getStore().load();" />
                    </Listeners>
                </ext:GridPanel>
                <ext:Panel ID="Panel1" runat="server" Region="Center" Border="false" Frame="true"
                    Layout="FitLayout" AutoScroll="false">
                    <Items>
                    </Items>
                </ext:Panel>
            </Items>
        </ext:Viewport>
        </form>
    </body>
    </html>
    Last edited by vadym.f; Apr 23, 2013 at 4:53 PM.
  4. #4
    Thank you for the sample.

    Agree, there is some inconsistency.

    To get it more (but not 100%) consistent, I would try to add a Buffer for the Update listeners.
    <Update Fn="onUpdateFilter" Buffer="100" />
    From one side it eliminates double executing of onUpdateFilter function.

    From another side it should guarantee that an Update listener is executed after an Activate and an Deactivate ones. If needed, you could check a filter's status (active or not within an Update listener).

    Agree it doesn't make the things 100% consistent, but it should allow you to write more universal JavaScript code to handle those events. Is it your objective, right?
  5. #5
    Sorry, I'm not sure if the Buffer made any difference.
  6. #6
    Well, there is some difference, but agree, it is definitely not that you are looking for.

    Please try the following override.

    Fix
    <script type="text/javascript">
        Ext.ux.grid.filter.DateFilter.override({
            onCheckChange : function () {
                if (this.active && this.isActivatable()) {
                    this.fireEvent('update', this);
                }
                this.setActive(this.isActivatable());
            },
    
            onMenuSelect : function (menuItem, value, picker) {
                var fields = this.fields,
                    field = this.fields[menuItem.ownerCt.itemId];
            
                field.setChecked(true, true);
            
                if (field == fields.on) {
                    fields.before.setChecked(false, true);
                    fields.after.setChecked(false, true);
                } else {
                    fields.on.setChecked(false, true);
                    if (field == fields.after && fields.before.menu.picker.value < value) {
                        fields.before.setChecked(false, true);
                    } else if (field == fields.before && fields.after.menu.picker.value > value) {
                        fields.after.setChecked(false, true);
                    }
                }
    
                this.fireUpdate();
            }
        });
    </script>
  7. #7
    Thanks a lot for this solution Daniil! I've made slight changes to the override to bring the check item event logic in line with the date picker menus' one.
    It seems that combining this thread with http://forums.ext.net/showthread.php...ional-behavior would make a perfect sense.

    Ext.ux.grid.filter.DateFilter.override({
        menuItems: ['after', 'before', '-', 'on'],
    
        onCheckChange: function (checkItem, value, options) {
            var fields = this.fields,
                    field = this.fields[checkItem.menu.itemId],
                    selectedPicker = field.menu.picker,
                    beforePicker = fields.before.menu.picker,
                    afterPicker = fields.after.menu.picker;
    
            // Important! Set hideOnClick to "false" in order for the menu to stay up!
            checkItem.hideOnClick = false;
    
            if (field == fields.on) {
                fields.before.setChecked(false, true);
                fields.after.setChecked(false, true);
            } else {
                fields.on.setChecked(false, true);
                if (field == fields.after && beforePicker.value < selectedPicker.value) {
                    fields.before.setChecked(false, true);
                } else if (field == fields.before && afterPicker.value > selectedPicker.value) {
                    fields.after.setChecked(false, true);
                }
            }
    
            if (this.active && this.isActivatable()) {
                this.fireEvent('update', this);
            }
            this.setActive(this.isActivatable());
        },
    
        onMenuSelect: function (menuItem, value, picker) {
            var fields = this.fields,
                    field = this.fields[menuItem.ownerCt.itemId];
    
            field.setChecked(true, true);
    
            if (field == fields.on) {
                fields.before.setChecked(false, true);
                fields.after.setChecked(false, true);
            } else {
                fields.on.setChecked(false, true);
                if (field == fields.after && fields.before.menu.picker.value < value) {
                    fields.before.setChecked(false, true);
                } else if (field == fields.before && fields.after.menu.picker.value > value) {
                    fields.after.setChecked(false, true);
                }
            }
    
            this.fireUpdate();
        }
    });
    
    var onActivateFilter = function (filter, options) {
        //alert('act');
    };
    
    var onUpdateFilter = function (filter, options) {
        //alert('upd');
    };
    
    var onDeactivateFilter = function (filter, options) {
        //alert('deact');
        filter.suspendEvents(false);
        switch (filter.type) {
            case "boolean":
                break;
            case "date":
                filter.menu.items.each(function (item) {
                    if (item instanceof Ext.menu.CheckItem)
                        item.setChecked(false);
                });
                break;
            case "list":
                filter.menu.items.each(function (item) {
                    item.setChecked(false);
                });
                break;
            case "numeric":
                filter.menu.items.each(function (item) {
                    if (item instanceof Ext.form.NumberField)
                        item.setValue("");
                });
                break;
            case "string":
                filter.menu.items.each(function (item) {
                    item.setValue("");
                });
                break;
        };
        filter.resumeEvents();
    
        // Do some other processing here;
    };
                                
    <ext:DateFilter DataIndex="UpdatedDate">
             <DatePickerOptions runat="server" TodayText="Now">
                       <CustomConfig>
                                 <ext:ConfigItem Name="hideOnClick" Value="false" Mode="Raw" />
                        </CustomConfig>
             </DatePickerOptions>
             <Listeners>
                       <Deactivate Fn="onDeactivateFilter" />
                       <Activate Fn="onActivateFilter" />
                        <Update Fn="onUpdateFilter" />
             </Listeners>
    </ext:DateFilter>
    Last edited by vadym.f; Apr 25, 2013 at 3:45 PM. Reason: Code update
  8. #8
    Nice. Thanks for sharing the final solution!
  9. #9
    Thanks again Daniil, the resulting behavior feels even more consistent than in v2.2 at https://examples2.ext.net/default.as...Filters_Local/! I made a slight but important update to the code posted above. Now the filter menu stays up and its check items logic is in sync with the date pickers selection!

Similar Threads

  1. DateFilter: Before, After and On all active
    By cwolcott in forum 2.x Help
    Replies: 3
    Last Post: Mar 13, 2012, 5:55 PM
  2. How to add event mask for listeners
    By rasu_13 in forum 1.x Help
    Replies: 0
    Last Post: Mar 31, 2010, 3:16 AM
  3. Multiple listeners for combobox select event
    By signup in forum 1.x Help
    Replies: 2
    Last Post: Nov 03, 2009, 1:31 PM
  4. Replies: 1
    Last Post: Sep 11, 2009, 11:41 AM
  5. Replies: 0
    Last Post: Apr 14, 2009, 6:10 PM

Tags for this Thread

Posting Permissions