I've been creating reusable components as jQuery plugins for projects for some time now. I like being able to abstract away the logic, and inject all of the context (selectors, options, etc) on a case-by-case basis.
Now, I'm starting to use KnockoutJS, and have written a nice little jQuery plugin that uses Knockout for its internal logic. It works quite well, but I'm wondering if there is a better way to do it? Does Knockout itself have a pattern/convention for creating reusable components, or is this pattern okay?
Here is an example, it should be enough to give you the idea of what I'm doing.
/*globals jQuery, knockout */
(function ($, ko) {
"use strict";
$.fn.itemManager = function (options) {
// set up the plugin options
var opts = $.extend({}, $.fn.itemManager.defaultOptions, options),
$wrap = $(this),
templateUrl = '/path/to/template/dir/' + opts.templateName + '.html';
// set up the KO viewmodel
function ItemManagerModel(items) {
var self = this;
self.items = ko.observableArray(items);
self.chosenItemId = ko.observable();
self.chosenItemData = ko.observable();
// generic method for navigating the Item hierarchy
self.find = function (array, id) {
/* ... */
};
/* bunch of other stuff... */
self.goToItem(items[0]);
}
// this is where the whole thing starts...
$(opts.openTriggerSelector).click(function (e) {
e.preventDefault();
// set the template html
$.get(templateUrl, function (data) {
$wrap.html(data);
});
// initial load and binding of the data, in reality I have some more conditional stuff around this...
// there's probably a better way to do this, but I'll ask in a separate question :)
$.get(opts.getItemsServiceUrl, function (result) {
ko.applyBindings(new ItemManagerModel(result), document.getElementById($wrap.attr('id')));
$wrap.data('bound', true);
});
// opens the template, which now is bound to the data in a dialog
$wrap.dialog({ /* ... */ });
// provide default plugin options
$.fn.itemManager.defaultOptions = {
getItemsServiceUrl: '/path/to/service',
openTriggerSelector: 'a',
templateName: 'Default'
};
} (jQuery, ko));
I run a github project for KO components. It's using an older version of KO and is due for a major revamp but you may be able to get some ideas. I basically do it all through custom bindings that take model objects as their configuration and data.
I am always on the lookout for a better way of doing this. Keep me posted if you come up with a better way.
https://github.com/madcapnmckay/Knockout-UI
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With