Visualizzazione post con etichetta mvvm. Mostra tutti i post
Visualizzazione post con etichetta mvvm. Mostra tutti i post

lunedì 14 maggio 2012

Custom bindings rulez (again)

Continua l'implementazione di custom bindings per BS/KO (vd. Tre piccioni con un custom binding). Questa volta mi occorreva simulare il comportamento tipico del checkbox/toggle e di un gruppo di radiobuttons utilizzando però i button di BS.
Qui il binding:
/*****************************
** KnockOut Custom Binding for Bootstrap common property .active
** Author: lightwalker
** Usage:
** a)  VM property is a bool -> data-bind="bsActive: [vmpropertyname]" 
**     for example togglebutton (checkbox behavior)
** b)  two parameters -> data-bind="bsActive: {value: [viewvalue], property: [vmpropertyname]}"
**     for example buttons group (radiobuttons behavior)
** http://twitter.github.com/bootstrap/javascript.html#buttons
*******************************/

        ko.bindingHandlers.bsActive = {
            'init': function (element, valueAccessor, allBindingsAccessor) {
                var updateHandler = function () {
                    var valueToWrite = null;
                    var modelValue = null;
                    if (valueAccessor().value != undefined) {
                        modelValue = valueAccessor().property;
                        valueToWrite = ko.utils.unwrapObservable(valueAccessor().value);
                    }
                    else {
                        modelValue = valueAccessor();
                        valueToWrite = !ko.utils.unwrapObservable(modelValue);
                    }


                    if (ko.isWriteableObservable(modelValue) && modelValue !== valueToWrite) {
                        modelValue(valueToWrite);
                    }
                };
                ko.utils.registerEventHandler(element, "click", updateHandler);
            },
            'update': function (element, valueAccessor) {
                    var valueToCompare = null;
                    var modelValue = null;
                    var toToggle = true;
                    if (valueAccessor().value != undefined) {
                        modelValue = ko.utils.unwrapObservable(valueAccessor().property);
                        valueToCompare = ko.utils.unwrapObservable(valueAccessor().value);
                        toToggle = (modelValue.toString() == valueToCompare.toString());
                    }
                    else {
                        toToggle = ko.utils.unwrapObservable(valueAccessor());
                    }
                    $(element).toggleClass('active', toToggle);
                }
       }
E qui il frammento di view:
<!-- int value binding -->
<div class="btn-group">
  <button class="btn" data-bind="bsActive: {value: 0, property: intVMObservable}">Value 0</button>
  <button class="btn" data-bind="bsActive: {value: 1, property: intVMObservable}">Value 1</button>
  <button class="btn" data-bind="bsActive: {value: 2, property: intVMObservable}">Value 2</button>
</div>
<!-- bool value binding -->
<button class="btn" data-bind="bsActive:boolVMObservable">Yes/No</button>

martedì 8 maggio 2012

Tre piccioni con un Custom Binding

Sulla falsariga dei Custom Bindings di Knockout per jQueryUI trovati qui e qui ne ho implementato uno per il PopOver di Bootstrap.

L'obiettivo principale era, ovviamente, rispettare il pattern MVVM anche nell'uso del framework di Twitter ed evitare che l'iniezione asincrona nel DOM di pezzi di UI rompesse l'applicazione del plugin al $(document).ready().
Mi si è aperta, però, un'altra possibilità...

I Popovers di BS non supportano nativamente l'opzione target, come invece fanno i Modals.
E questo è un peccato: definire direttamente nel markup il contenuto html è, di nuovo, perfettamente compliant al MVVM e offre una flessibilità impagabile.
Ho quindi delegato al binding la valorizzazione del content nei due casi:

  • che sia valorizzata l'opzione content
  • che sia valorizzata l'opzione target (non nativa) con il selettore di un oggetto definito nel DOM

Qui il binding:
/**
KnockOut Custom Binding for Bootstrap Popovers (http://twitter.github.com/bootstrap/javascript.html#popovers)
Author: lightwalker
**/

(function ($) {

    if (ko && ko.bindingHandlers) {

        ko.bindingHandlers.bsPopover = {
            init: function (element, valueAccessor) {
                var val = ko.utils.unwrapObservable(valueAccessor());
                var options = { title: val.title,
                    animation: val.animation,
                    placement: val.placement,
                    trigger: val.trigger,
                    delay: val.delay,
                    //can grab html content from a target option
                    content: ($(val.target).html() != null) ? $(val.target).html() : val.content
                };
                $(element).popover(options);
            }
        };

    };

})(jQuery);
E qui il frammento di view:
<!-- popover activator -->
<a href="#" class="btn btn-danger" rel="popover" data-bind="bsPopover:{title: vmObservable(), target:'#popover-content'}">Hover Me!</a>
<!-- popover html content -->
<div id="popover-content" class="hide"><b>Custom HTML Content</b></div>
E allora... Buon binding a tutti!

Edit: continua con: Custom bindings rulez (again)