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();