Knockout 3.x binding handler 'update' test

Demonstrates that, even with v3.x, it appears that multiple bindings on an element will cause all of those bindings's update method to fire whenever any of the bound values gets updated.

by jasonkylefrank

HTML

<script src="http://knockoutjs.com/downloads/knockout-3.1.0.js"></script>
<div id="ProgressWrapper"
     data-bind="slideVisibleDelayedHide: ShouldShowLoadingProgress,
                slideDuration: 340, slideHideDelay: 1700,
                css: { 'LoadingComplete': (IsItemsLoading() == false) }"
             style="display: none;" >  <!--  -->
    <h3 class="progressHeader" data-bind="text: LoadingProgressHeaderText"></h3>
    <div>
        <label data-bind="text: Items().length"></label><label> of </label>
        <label data-bind="text: limit"></label><label> loaded.</label>
    </div>
</div>

<input type="button" value="Get New Items" 
       data-bind="click: function() { GetNewItems(0); }, enable: !IsItemsLoading()" /> 
<table>
    <thead>
        <th>Item Name</th><th>Item Description</th>
    </thead>
    <!-- ko foreach: Items -->
    <tbody>
      <tr>
        <td data-bind="text: Name"></td>  <td data-bind="text: Description"></td>
      </tr>
    </tbody>
    <!-- /ko -->
</table>

CSS

#ProgressWrapper {
    border: 1px solid #999;
    background: #ddd;
    margin-bottom: 20px;
    padding: 10px;
}
#ProgressWrapper.LoadingComplete {
    border: 1px solid #22aa22; /* Green */
    background: #f0fff0;       /* slight green */
}
table { margin-top: 20px; }
td {    
    border: 1px solid #aaa;
    padding: 5px;
}

JavaScript

///<summary>Similar to slideVisible, but delays the slideUp() after the value turns to false to 
/// allow the user to see something before the item disapears. Useful for things like a status 
/// message which turns to "process complete" and then delays the slideUp() for a second or two so that 
/// the user sees the "process complete" message.</summary>
ko.bindingHandlers.slideVisibleDelayedHide = {
    init: function (element, valueAccessor) {            
    },
    update: function (element, valueAccessor, allBindingsAccessor) {
        // First get the latest data that we're bound to
        var newValue = ko.utils.unwrapObservable(valueAccessor()), allBindings = allBindingsAccessor();
        console.log("slideVisibleDelayedHide 'update' called, with new value: " + newValue);
        // Grab some more data from other binding properties
        var duration = allBindings.slideDuration || 400; // 400ms is default duration unless otherwise specified
        var hideDelay = allBindings.slideHideDelay || 2000;

        // Workaround for Knockout 2.x issue of firing ALL binding on the same element when ANY of their 
        //  bound values change: Only do these actions if the bound value is actually different than it 
        //  was last time (in other words, only act when it logically makes sense that the bindings 'update'
        //  should be called).
        var valueHasChanged = element.ko_slideVisibleDelayedHide_currentValue != newValue;
        
        if (valueHasChanged) {
            // Now manipulate the DOM element
            if (newValue == true) {
                // Cancel a scheduled hide action since the value has been toggled to true again 
                //  (the scheduled hide would negate this show action after a short delay)
                if (typeof element.ko_slideVisibleDelayedHide_timeoutId !== 'undefined')
                    clearTimeout(element.ko_slideVisibleDelayedHide_timeoutId);

               ...