1

I'm using a module pattern for my jQuery / javascript code and I'm using self executed functions for it as I'm doing for Knockout.js. (same as in the official knockout.js tutorials).

This is probably a very subjective question to ask, but I would like to know what's your point of view on it and how knockout guys usually deal with this problem in their web applications.

It is not easy to find information about this topic.

Would you mix together in the same module the knockout.js logic and the jQuery events and functions? Or would you separate it in different files and different modules?

Also, sometimes some events are not easy to bind in knockout:

  • scroll / mousewheel events
  • Bootstrap events $('#demo').on('shown.bs.modal', whatever);
  • Plugin events: $('#demo').bind('typeahead:select', whatever);
  • Not easy to retrieve the object $(this) in a proper way

As an example, lets suppose I have this module to deal with client orders:

function order(){
    var self = this;

    for(var key in data) {
        if(!self.hasOwnProperty(key)) {
            self[key] = data[key];
        }
    }
}
function ordersViewModel(){
    var self = this;
    self.orders = ko.observableArray([]);

    //get the orders for the given date range
    self.getOrders = function(from, to){
        $.get(myUrl + 'orders/getOrders/', function(data){
            self.orders(data.map(function(ordersData) {
                return new order(ordersData);
            }));
        });
    };
}

var MasterModel = function(){
    this.orders = new ordersViewModel()
};

var mm = new MasterModel();

ko.applyBindings(mm);

Then, I have an Orders module to deal with all the jQuery events and actions over the orders element in the screen, this is separated from the knockout.js module:

function orders() {
    var self = this;
    self.tableWrapper = $('#orders-table-wrapper');

    self.init = function () {
        self.bindEvents();
        self.initTypeahead();
    };

    self.bindEvents = function () {
        //when actions menu is hidden
        self.tableWrapper.on('hide.bs.dropdown', '.dropdown', self.unSelectActions);

        $(document).on("contextmenu", "#orders-table-wrapper table > tbody > tr", self.showContextMenu);

        $('#ordersSearch').change(self.search).keyup(function () {            
            //forcing input change
            $(this).change();
        });

        $('#equipment-id-input').bind('typeahead:select', function (ev, suggestion) {
            $('#equipment-id-input').trigger('change');
        });
    };

    //when actions menu is hidden
    self.unSelectActions = function () {
        $(this).find('.moreActions').removeClass('active');
    };

    //context menu for orders table
    self.showContextMenu = function(event){
        //whatever
    }

    //table filtering
    self.search = function(){
        //whatever
    }
}

var myModels = function(){
    this.orders = new orders().init();
};

var myMasterModel = new myModels();
Alvaro
  • 37,936
  • 23
  • 138
  • 304

1 Answers1

3

The cardinal rule of Knockout is: don't mess with the DOM outside of a binding handler. Mouse wheel events bind just fine, see here. For Bootstrap, there are bindings here. Plugins easily wrap in custom binding handlers (example).

I strongly recommend you familiarize yourself with custom binding handlers. Using Knockout for the basic stuff and jQuery for everything else is not going to be appreciably better than just using jQuery for everything (which creates a hot mess).

Community
  • 1
  • 1
Roy J
  • 37,999
  • 5
  • 58
  • 88
  • Thanks for the answer, I'll take a look at you links! Although I was trying not to use many 3rd party script such as the Knockout-Bootstrap because each one adds a layer to the app that has to be maintained and can potentially contain additional bugs or slow down the development when new version arise (BootStrap v4, for example). It seems its issues forum is not very active either... – Alvaro Sep 15 '15 at 13:58
  • What about the "Not easy to retrieve the object $(this) in a proper way"? Any solution for it? I can bind something on click, but retrieving the element is not perfect... – Alvaro Sep 15 '15 at 14:44
  • @Alvaro In a binding handler, you are passed the DOM element being bound. i'd need an example of what you're trying to do. – Roy J Sep 15 '15 at 16:54
  • I guess there's no much difference between using a knockout custom binding handler and just using a `init` method calling a `bindEvent` method containing all the bindings in jQuery. http://jsfiddle.net/o6m4wv8v/ – Alvaro Sep 29 '15 at 11:55