Hybrid View

  1. #1
    Sencha - Community Support Team mystix's Avatar
    Join Date
    Mar 2007
    Location
    Singapore
    Posts
    6,236
    Vote Rating
    5
    mystix will become famous soon enough

      0  

    Default [Solved] [1.0.1a / 1.1] DateField change event bugs + proposed fixes

    [Solved] [1.0.1a / 1.1] DateField change event bugs + proposed fixes


    the DateField's blur event fails to fire if the DatePicker is clicked immediately after clicking in the DateField.

    a test case follows:
    HTML Code:
    <html>
    <head>
      <link rel='stylesheet' href='ext-all.css'>
    
      <script src='yui-utilities.js'></script>
      <script src='ext-yui-adapter.js'></script>
      <script src='ext-all-debug.js'></script>
      
      <script>
        Ext.onReady(function() {
          var df = new Ext.form.DateField({
            format: 'd/m/y',
            listeners: {
              blur: function(o) {
                console.log('lost focus!');
              }
            }
          });
          df.applyTo('myDate');
        });
      </script>
    </head>
    <body>
    <input type='text' id='myDate' value='07/07/07'/>
    <input type='text' id='otherField' value='The Other Field'/>
    </body>
    </html>
    • click in the DateField, then click in "The Other Field", and console.log fires.
    • click directly on the DatePicker, then click in "The Other Field", and console.log also fires.
    • click in the DateField, then click on the DatePicker icon, then click in "The Other Field", and console.log doesn't fire -- another click is required anywhere outside the DateField and DatePicker before console.log fires again.

  2. #2
    Sencha User jack.slocum's Avatar
    Join Date
    Mar 2007
    Location
    Tampa, FL
    Posts
    6,955
    Vote Rating
    17
    jack.slocum will become famous soon enough jack.slocum will become famous soon enough

      0  

    Default


    That is how most "windowed" controls work in windows as well. The first click hides the picker, another click actually blurs the field. Only in windows they also refocus the field. To see what I mean, go to http://extjs.com/deploy/ext/examples/form/dynamic.html and expand the theme select box. While it is expanded, click on a field. Notice how the focus stays on the select.

    I changed the hide function on menuListeners to do:

    this.focus.defer(10, this);

    instead of a direct focus and it appears to have the same affect. I'm just not sure this is the most desirable behavior.
    Jack Slocum
    Ext JS Founder
    Original author of Ext JS 1, 2 & 3.
    Twitter: @jackslocum
    jack@extjs.com

  3. #3
    Sencha - Community Support Team mystix's Avatar
    Join Date
    Mar 2007
    Location
    Singapore
    Posts
    6,236
    Vote Rating
    5
    mystix will become famous soon enough

      0  

    Default


    Once again, you're right. The default behaviour for "windowed" controls is as you say. Errm... perhaps the change should be undone if the behaviour is not very desirable? Sorry about that.

    My original intention was to listen for the DateField's 'change' event, which isn't firing correctly for me.
    To test this, change the listener above from 'blur' to 'change'. Click in the DateField, then click on anything other than the DateField and DatePicker, and the 'change' event is fired even when nothing is changed i.e. it works just like the 'blur' event.

    I did some testing on the 'change' event for a TextField, and it works flawlessly:
    HTML Code:
    <html>
    <head>
      <link rel='stylesheet' href='ext-all.css'>
    
      <script src='yui-utilities.js'></script>
      <script src='ext-yui-adapter.js'></script>
      <script src='ext-all-debug.js'></script>
      
      <script>
        Ext.onReady(function() {
          var tf = new Ext.form.TextField({
            listeners: {
              change: function(o) {
                console.log('changed!');
              }
            }
          });
          tf.applyTo('myText');
        });
      </script>
    </head>
    <body>
    <input type='text' id='myText' value='Some Text'/>
    </body>
    </html>
    so maybe there's something in DateField / TriggerField that's causing this unexpected behaviour?

  4. #4
    Sencha - Community Support Team mystix's Avatar
    Join Date
    Mar 2007
    Location
    Singapore
    Posts
    6,236
    Vote Rating
    5
    mystix will become famous soon enough

      0  

    Default


    Quote Originally Posted by mystix View Post
    My original intention was to listen for the DateField's 'change' event, which isn't firing correctly for me.
    To test this, change the listener above from 'blur' to 'change'. Click in the DateField, then click on anything other than the DateField and DatePicker, and the 'change' event is fired even when nothing is changed i.e. it works just like the 'blur' event.
    i'm reopening this issue 'cos i've encountered this issue again in Ext 1.1 final.
    (change event for a DateField with an existing value is fired even though the date remains the same).

    i've managed to trace it down to Ext.form.Field's onBlur method
    Code:
    onBlur : function() {
      this.beforeBlur();
      this.el.removeClass(this.focusClass);
      this.hasFocus = false;
      if (this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur") {
        this.validate();
      }
      var v = this.getValue();
      if (v != this.startValue) { // here's the problem
        this.fireEvent('change', this, v, this.startValue);
      }
      this.fireEvent("blur", this);
    }
    (refer to the red section in the code block above) the DateField sets both v and this.startValue correctly. the == operator, on the other hand, does not work correctly on these 2 Date objects v and this.startValue.

    try this in the FireBug console to see what i mean.
    Code:
    var dt = new Date(2007, 7, 4);
    new Date(2007, 7, 4) == new Date(2007, 7, 4); // returns false
    dt == dt; // returns true

    [edit]
    attached below is a test case.
    change the date to 200807,then tab / click anywhere outside the DateField to see the problem.
    HTML Code:
    <html>
    <head>
      <link rel='stylesheet' href='resources/css/ext-all.css'>
    
      <script src='adapter/ext/ext-base.js'></script>
      <script src='ext-all-debug.js'></script>
      
      <script>
        Ext.onReady(function() {
          var df = new Ext.form.DateField({
            dateFormat: 'dmy',
            listeners: {
              change: function(o, newVal, oldVal) {
                console.log('date was changed from ', oldVal, ' to ', newVal);
              }
            }
          });
          df.applyTo('myDate');
        });
      </script>
    </head>
    <body>
      <input type='text' id='myDate'/>
    </body>
    </html>
    Last edited by mystix; 7 Aug 2007 at 12:49 AM. Reason: removed buggy proposed fix

  5. #5
    Sencha - Community Support Team mystix's Avatar
    Join Date
    Mar 2007
    Location
    Singapore
    Posts
    6,236
    Vote Rating
    5
    mystix will become famous soon enough

      0  

    Default


    fiddled some more and came up with a non-buggy proposed fix (i've removed the previous buggy one from the previous post)

    this proposed fix involves abstracting out the comparison which fires the change event in the Ext.form.Field's onBlur method, and overriding this comparison in the Ext.form.DateField to handle Date object comparisons.

    [proposed fix]
    Code:
    Ext.override(Ext.form.Field, {
      // abstract out the comparison which fires the change event in the onBlur method
      equalsStartValue: function(v) { // returns true if v = this.startValue
        return v == this.startValue;
      },
      
      onBlur : function() {
        this.beforeBlur();
        this.el.removeClass(this.focusClass);
        this.hasFocus = false;
        if (this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur") {
          this.validate();
        }
        var v = this.getValue();
        if (!this.equalsStartValue(v)) { // use comparison function instead of v != this.startValue
          this.fireEvent('change', this, v, this.startValue);
        }
        this.fireEvent("blur", this);
      }
    });
    
    Ext.override(Ext.form.DateField, {
      menuListeners : {
        select: function(m, d) {
          this.setValue(d);
        },
        show : function() {
          this.onFocus();
        },
        hide : function() {
          (function() { // fix to fire change event when date is changed via DatePicker menu
            this.el.un("focus", this.onFocus, this);
            this.focus();
            this.el.on("focus", this.onFocus, this);
          }).defer(10, this);
          var ml = this.menuListeners;
          this.menu.un("select", ml.select,  this);
          this.menu.un("show", ml.show,  this);
          this.menu.un("hide", ml.hide,  this);
        }
      },
    
      
      // custom comparison function for Date objects
      equalsStartValue: function(v) {
        return (v)? Date.parse(v) == Date.parse(this.startValue) : !v && !this.startValue;
      }
    });
    tested in Ext 1.1 final.
    Last edited by mystix; 7 Aug 2007 at 11:06 PM. Reason: added fix to fire change event when date is changed via DatePicker menu

  6. #6
    Sencha - Community Support Team mystix's Avatar
    Join Date
    Mar 2007
    Location
    Singapore
    Posts
    6,236
    Vote Rating
    5
    mystix will become famous soon enough

      0  

    Default


    [edit]
    added fix to fire change event when date is changed via DatePicker menu