Jay Bienvenu
Jay Bienvenu

Reputation: 3293

Durandal: Making a module of custom Knockout bindings

I want to move all of the custom bindings that I create with composition.addBindingHandler out to a module, to keep my main.js method clean. I moved them to a file lib/binding/binding.js as shown below, created an alias binding for the file in requirejs.config(), and replaced the calls with a call to require('binding'). However, this code throws the error Module name "binding" has not been loaded yet for context: _. Use require([]). How do I change this code to work properly?

app.start() call

app.start().then(function() {
    //Replace 'viewmodels' in the moduleId with 'views' to locate the view.
    //Look for partial views in a 'views' folder in the root.
    viewLocator.useConvention();

    require('binding'); 
    //PRIOR: var composition = require('durandal/composition');
    //PRIOR: composition.addBindingHandler() calls that now live in lib/binding/binding.js.

    $.when(config.init()).then(function () {
        //Show the app by setting the root view model for our application with a transition.
        app.setRoot('viewmodels/shell'); 
    })

});

lib/binding/binding.js (probably doesn't matter but is included for completeness)

; (function (define) {
    define(['durandal/composition', 'knockout', 'datepicker'], function (composition, ko, datepicker) {

        // The following code originally resided in main.js after this declaration:
        // var composition = require('durandal/composition');

        // hidden: Inverse of 'visible'.
        composition.addBindingHandler('hidden', {
            update: function (element, valueAccessor) {
                var value = ko.utils.unwrapObservable(valueAccessor());
                ko.bindingHandlers.visible.update(element, function () { return !value; });
            }
        });

        // datepicker: Reusable form element with date picker.
        composition.addBindingHandler('datepicker', {
            init: function (element, valueAccessor) {
                var input = $("<input type=\"text\" class=\"form-control datepicker\" placeholder=\"MM/DD/YYYY\" />");
                var span = $("<span class=\"input-group-addon\"><i class=\"fa fa-calendar\"></i></span>");
                input.datepicker();
                input.appendTo(element);
                span.appendTo(element);
            }
        });

    });
})();

Upvotes: 3

Views: 1121

Answers (1)

PW Kad
PW Kad

Reputation: 14995

I often just wrap my bindings in an empty module that returns nothing like so -

define([],
    function () {

        // Convert any date to a MM-DD-YYYY format with moment.js
        ko.bindingHandlers.Date = {
            update: function (element, valueAccessor) {
                var value = valueAccessor();
                var date = moment(value());
                var strDate = date.format('MM/DD/YYYY');
                $(element).text(strDate);
            }
        };
    });

Then just require it in your shell.js module

define(['services/bindings'], function (bindings) {

});

That's all you need to do. In a nutshell you are just using the module to register the custom bindings onto the instance of Knockout.

Upvotes: 6

Related Questions