Friday, August 30, 2013

Knockout Custom Bindings in Durandal


Instead of using like

$("#mask").inputmask ("d/m/y" , {autoUnmask : true});


it is better to use knockout custom binding.

Define the custom binding in html or make an AMD module.

ko.bindingHandlers.inputmask = {
  init: function (element, valueAccessor, allBindingsAccessor) {
    var obj = valueAccessor(),
              allBindings = allBindingsAccessor(),
              format = allBindings.format;
    $(element).inputmask(format , obj);

    ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
      $(element).inputmask('destroy');
    });
  },
  update: function (element) {
    $(element).trigger('change');
  }
};
or define this in main module.


define(['durandal/system', 'durandal/app', 'durandal/viewLocator' , 'durandal/composition'], function (system, app, viewLocator , composition) {

 composition.addBindingHandler('inputmask', {
        init: function (element, valueAccessor, allBindingsAccessor ) {
              var obj = valueAccessor(),
                  allBindings = allBindingsAccessor(),
                  format = allBindings.format;
              $(element).inputmask(format , obj);


               ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
                 $(element).inputmask('destroy');
               });           

        },
        update: function (element) {
            $(element).trigger('change');
        }
    });
......
}
And you can use in view as:
< input data-bind="inputmask :  {autoUnmask: true} , format : 'd/m/y'" id="mask" type="text" / >

Use Non AMD Javascript Libraries in Durandal 2.0


By using shim, jquery libraries can be used in Durandal.

In the main js, configure shim. I have written a module UIInitialize to intialize the interface. This is dependant on jQuery, jQueryGritter and jQueryPulsate.

requirejs.config({
    urlArgs: "bust=" + (new Date()).getTime(),
    paths: {
        'text': '../Scripts/text',
        'durandal': '../Scripts/durandal',
        'plugins': '../Scripts/durandal/plugins',
        'transitions': '../Scripts/durandal/transitions',
        'jQueryGritter': '../Scripts/gritter/js/jquery.gritter',
        'jQueryPulsate': '../Scripts/jquery.pulsate.min',
        'UIInitialize': '../Scripts/UIGeneral',
    },
    shim: {
        'UIInitialize': {
            deps: ['jquery', 'jQueryGritter', 'jQueryPulsate'],
            exports: 'UIInitialize'
        }
    }
});

The UIInitialize.js is as below:

var UIInitialize = function () {
    return {
          init: function () { 
               // Initialize gritter and pulsate
          }
    };
}();


Dynamic router in Durandal 2.0


The router configuratin is in the shell.js file. I need to make this router dynamically managable. To do so, I have used ajax.

The change is in the active method in shell.js file.

activate: function () {
   var routes = [];
 
   $.ajax({
       url: "/Route/Get",
       async: false,
       dataType  : 'json'
       }).done(function (response) {
       routes = response;
   });
 
   router.map(routes).buildNavigationModel();
   return router.activate();
}

The server code is as below.
 public JsonResult Get()
  {
     List route = new List()
     {
        new Route(){ route = "" ,
            title = "Welcome", moduleId = "viewmodels/welcome", nav= true },
        new Route(){ route = "flickr" ,
            moduleId = "viewmodels/flickr" , nav= true }
     };

     return Json(route , JsonRequestBehavior.AllowGet);
}



Managing Css Files in Durandal 2.0


Durandal does not have a mechanism to manage css file for each view. So I have created a plugin to manage css files.

The plugin is as below. I have placed this plugin under durandal/plugins folder

define(['jquery'], function ($) {
    return {
        loadCss : function (fileName) {
            var cssTag = document.createElement("link")
            cssTag.setAttribute("rel", "stylesheet")
            cssTag.setAttribute("type", "text/css")
            cssTag.setAttribute("href", fileName)
            cssTag.setAttribute("class", "__dynamicCss")

            document.getElementsByTagName("head")[0].appendChild(cssTag)
        },
        removeModuleCss: function () {
            $(".__dynamicCss").remove();

        }
    };
});


In the viewmodel, I have used is as below.

define(['plugins/cssLoader'], function (cssLoader) {
    var ctor = function () {
        this.compositionComplete =  function () {
            cssLoader.loadCss("sample.css");
            cssLoader.loadCss("sample2.css");

            // Recommendation : Use Bundle
        };
        this.deactivate =  function () {
            cssLoader.removeModuleCss();
        }
    };

    return ctor;
});