使用Knockout.js动态模板处理

时间:2014-12-01 15:12:58

标签: javascript knockout.js

我试图在Knockout中创建一个表组件,它可以以仍然使用Knockout来获取单元格内容的方式呈现任意列。我将一个列定义对象数组传递给组件和一个任意行对象的数组。然后,我有一个嵌套的foreach结构,看起来有点像这样:

<tbody data-bind="foreach: {data:rows, as:'row'}">
  <tr data-bind="foreach: $parent.columns">
    <td data-bind="html:renderCell(row)"></td>
  </tr>
</tbody>

有了这个,我可以允许'renderCell&#39;给定行viewModel的上下文,每个列的函数返回一些html进入单元格。

然而,我真正想要的是能够返回单元格的Knockout模板。我不想使用<script type="text/html" id="xyz">样式模板,因为它不适合这个特定的应用程序,但我无法弄清楚如何让Knockout将renderCell()的输出视为模板字符串。

我如何做以下的事情并使其有效?

<td data-bind="template:{fn: renderCell(row)}"></td>

我想在renderCell函数的输出中使用其他组件和其他绑定。

1 个答案:

答案 0 :(得分:1)

据我了解,您需要为每个单元格定制一个模板。此模板将基于进入绑定的信息。我能想到让你这样做的壁橱是一个自定义绑定处理程序:

ko.bindingHandlers.yourBindingName = {
    init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        // This will be called when the binding is first applied to an element
        // Set up any initial state, event handlers, etc. here
    },
    update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        // This will be called once when the binding is first applied to an element,
        // and again whenever any observables/computeds that are accessed change
        // Update the DOM element based on the supplied values here.
    }
};

这是淘汰文档中的基本内容。我猜想在init函数中你可以选择一些你想要显示的html:

function customTemplateOne(dataToBind) {
    var spanEl = document.createElement('span');
    spanEl.innerHTML = dataToBind;
    return spanEl;
}

您可以拥有一大堆不同的功能来定义不同的模板。

在你的初始化中你可以这样做:

var template = "";
switch (valueToDetermineTemplateChange)
{
    case "useThis":
        template = customTemplateOne(dataToBind);
}

或者您可以利用JavaScripts键值。

var templates = {
    useThis: function () {}
}

var template = templates[valueToDetermineTemplateChange]();

要进行自定义选项,您可以执行以下操作:

ko.bindingHandlers.yourBindingName = {
    init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        // This will be called when the binding is first applied to an element
        // Set up any initial state, event handlers, etc. here

        var options = {};

        ko.extend(options, ko.bindingHandlers.yourBindingName); // get the global options
        ko.extend(options, ko.unwrap(valueAccessor())); // merge with the local options

        // so if you have a data property on the options which holds the ko binding you can do this:
        var data = ko.unwrap(options.data);
    },
    update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        // This will be called once when the binding is first applied to an element,
        // and again whenever any observables/computeds that are accessed change
        // Update the DOM element based on the supplied values here.
    },
    options: {
        customOption: "Some Option"
    }
};

<div data-bind="yourBindingName: { data: someValue }"></div>

而不是applyBindingsToDescendants函数,使init成为其他绑定的包装:

ko.applyBindingsToNode(element, { html: valueAccessor() }, context); // the html is a binding handler, you can specify with, text, foreach....