Wednesday, July 3, 2013

jQuery UI: Change Event Data For Progressbars

The progressbar widget, any time the value changes, will trigger a change event. This change in value happens when the value() method is used, or when the value option is set. Both produce the same result. But the progressbar doesn't automatically trigger the change event just because the value is updated. It has to actually change, to a different number. This is accomplished by storing the old value internally, and comparing it to the new value, and only when there is a difference does the change event trigger. What would be really useful is to include both the old and new values of the progressbar in the event data.

For example, suppose I have a label where I want to display the time of change, and how much change, each time the value is set on the progressbar. To do this, I'll override the _refreshValue() method, and here I can pass the data I need to my change event handler. This is the what the result looks like after I change the value of the progressbar.



And here is the code I used to do it.

(function( $, undefined ) {

// Customize the progressbar, using our own
// namespace.
$.widget( "ab.progressbar", $.ui.progressbar, {

    // Called when the progress bar value is set.  Even
    // if the value hasn't actually changed.
    _refreshValue: function() {

        // We need a reference to the old value.
        var oldValue = this.oldValue;
            value    = this.options.value;

        // This prevents _super() from triggering the
        // change event.  Even if the value has changed,
        // the default implementation of _refreshValue()
        // doesn't pass any data, so we will do so here.
        this.oldValue = value;

        this._super();

        // Has the value actually changed?
        if ( oldValue !== value ) {

            // Trigger the change event with our custom 
            // data.
            this._trigger( "change", null, {
                value: value,
                previous: oldValue 
            });

            this.oldValue = value;

        }
        else {
            
            this.oldValue = oldValue;

        }

    }

});

})( jQuery );

$(function() {

    // Create the progressbar with a change handler.    
    $( "#progressbar" ).progressbar({
        value: 10,
        change: function( e, ui ) {

            // We can easily compute the actual change now,
            // because of the data passed to the event in
            // our custom _refreshValue() implementation.
            var change = ui.value - ui.previous,
                time   = new Date().toLocaleTimeString(),
                label  = $( "<span/>" ).text( time );

            change = change > 0 ? "+" + change : change;

            $( "<strong/>" ).text( change )
                            .appendTo( label );

            $( "#changed" ).html( label );

        }

    });


});