Question

The subject is a little confusing, but here is what I'm trying to do:

I have created a KnockoutJS custom binding to display a grid on my page. This works well, I followed the SimpleGrid model on the site. However, some of my fields are dates, booleans, etc. I would like to use a custom binding to transform a date using the time ago plugin, etc. Before I built the grid I would simply assign the custom binding in the grid. Now that I am using a "reusable" grid binding I want to be able to pass in (as part of my column definitions) a list of bindings and values to assign in the template for the header and cells of my grid.

Here's the HTML in my page:

<div data-bind="grid: grid" />

Here's the HTML Page View Model:

 var tenantsViewModel = {
    navigateDetails: function (tenant) {
        document.location = '/Tenants/Details/' + tenant.TenantId;
    },
    navigateDomain: function (tenant) {
        window.open("http://" + tenant.Domain);
    },
    grid: new my.grid({
        resource: "system/tenants",
        columns: [
          { display: "Tenant", value: "Name", isLink: true },
          { display: "Enabled", value: "IsEnabled", isLink: false },
          { display: "Tenant Since", value: "CreatedOn", isLink: false },
          { display: "Domain", value: "Domain", isLink: true }
      ]
    })
};
tenantsViewModel.grid.update();
ko.applyBindings(tenantsViewModel);

Here's my custom grid binding and template:

// Object
my.grid = function (config) {
    var self = this;
    self.data = ko.observableArray([]);
    self.columns = config.columns;
    var resource = config.resource;

    my.grid.prototype.update = function () {
        // A Wrapper for $.ajax()/JSONP
        my.get(resource, function (data) {
            self.data(data);
        });
    };
};

// Templates
var templateEngine = new ko.nativeTemplateEngine();

templateEngine.addTemplate = function (templateName, templateMarkup) {
    document.write("<script type=\"text/html\" id='" + templateName + "'>" + templateMarkup + "<" + "/script>");
};

templateEngine.addTemplate("merlin_grid", "\
                <table class=\"data\">\
                    <thead>\
                        <tr data-bind=\"foreach: columns\">\
                           <th data-bind=\"text: display\"></th>\
                        </tr>\
                    </thead>\
                    <tbody data-bind=\"foreach: data\">\
                       <tr data-bind=\"foreach: $parent.columns\">\
                           <td data-bind=\"css: { link: isLink },text: typeof value == 'function' ? value($parent) : $parent[value] \"></td>\
                        </tr>\
                    </tbody>\
                </table>");

// Grid: Convert element into a full blown grid component
ko.bindingHandlers.grid = {
    init: function () {
        return { controlsDescendantBindings: true };
    },
    update: function (element, viewModelAccessor, allBindingsAccessor) {
        var viewModel = viewModelAccessor(), allBindings = allBindingsAccessor();

        while (element.firstChild)
            ko.removeNode(element.firstChild);

        var gridTemplateName = allBindings.gridTemplate || "merlin_grid";

        var gridContainer = element.appendChild(document.createElement("DIV"));
        ko.renderTemplate(gridTemplateName, viewModel, { templateEngine: templateEngine }, gridContainer, "replaceNode");
    }
};

Is there an easy way to do this?

Thanks

Was it helpful?

Solution

I was unable to get this to work. I've got a question out to the KnockoutJS user group as well. If they ever respond I'll post the result here.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top