Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating reusable components with KnockoutJS

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));
like image 754
Ian Robinson Avatar asked Nov 04 '22 04:11

Ian Robinson


1 Answers

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

like image 187
madcapnmckay Avatar answered Nov 07 '22 22:11

madcapnmckay