6

ノックアウトを使用して行と列を動的にレンダリングしたいと思います。アイデアは、各行にいくつかのセルを入力し、必要に応じて動的に行を追加したいということです。セルの総数が4*行数に等しいと仮定して、次のことを試しました。

<table>
    <tbody data-bind="foreach: model">
        <!--ko if: $index() % 4 == 0--><tr><!--/ko-->
         <td>
              <label data-bind="text: Value"></label>
         </td>
         <td>
              <input type="checkbox" data-bind="checked: IsChecked"/>
         </td>
         <!--ko if: $index() % 4 == 0--></tr><!--/ko-->
     </tbody>
 </table>

しかし、それはそれがそうであったように機能します:

<table>
    <tbody data-bind="foreach: model">
        <!--ko if: $index() % 4 == 0-->
         <td>
              <label data-bind="text: Value"></label>
         </td>
         <td>
              <input type="checkbox" data-bind="checked: IsChecked"/>
         </td>
         </tr><!--/ko-->
     </tbody>
 </table>

行全体をコンテンツでレンダリングしないことにより、ノックアウトですべてのセルをレンダリングし、必要な場合にのみ行を追加することは可能ですか?

回避策として、ネストされたforeachについて考えていますが、モデルを1次元から2次元に変更する必要があり、奇妙に思えます。

4

2 に答える 2

14

データを行に構造化する別の計算プロパティを追加します。

<table>
    <tbody data-bind="foreach: rows">
        <tr>
            <!-- ko foreach: $data -->
            <td data-bind="text:$index"></td>
            <td data-bind="text:fname"></td>
            <td data-bind="text:lname"></td>
            <!-- /ko -->
        </tr>
    </tbody>
</table>

コード付き:

var vm = {

    people: ko.observableArray([
        { fname: 'fname', lname: 'lname' },
        { fname: 'fname', lname: 'lname' },
        { fname: 'fname', lname: 'lname' },
        { fname: 'fname', lname: 'lname' }
    ])
};

vm.rows = ko.computed(function () {

    var itemsPerRow = 3, rowIndex = 0, rows = [];

    var people = vm.people();
    for (var index = 0; index < people.length; index++) {
        if (!rows[rowIndex])
            rows[rowIndex] = [];

        rows[rowIndex].push(people[index]);

        if (rows[rowIndex].length == itemsPerRow)
            rowIndex++;
    }

    return rows;
}, vm);

$(function () {
    ko.applyBindings(vm);
});
于 2012-12-18T02:29:58.280 に答える
3

DOMを使用しているという理由だけで、構文はノックアウトのデフォルトのテンプレートエンジンでは機能しません。これを行う必要がある場合は、文字列ベースの外部テンプレートエンジンを使用します(テンプレートを文字列として扱い、正規表現と文字列の操作を使用するため、開始/終了タグの条件付きレンダリングでこのトリックを実行できます)。アンダースコアjsを使用した例:

http://jsfiddle.net/2QKd3/5/

HTML

<h1>Table breaking</h1>
<ul data-bind="template: { name: 'peopleList' }"></ul>

<script type="text/html" id="peopleList">
    <table>
    <tbody>
    {{ _.each(model(), function(m, idx) { }}
        {{ if (idx % 4 == 0) { }}
            <tr>
        {{ } }}
         <td>

              <label>{{= m.Value }}</label>
         </td>
         <td>
             <input type="checkbox" data-bind="checked: m.IsChecked"/>
         </td>
        {{ if (idx % 4 == 3) { }}
        </tr>
        {{ } }}
    {{ }) }}
            </tbody>
            </table>
</script>

Javascript(これには、ここで説明されているアンダースコアの統合が含まれます-http ://knockoutjs.com/documentation/template-binding.html

_.templateSettings = {
    interpolate: /\{\{\=(.+?)\}\}/g,
    evaluate: /\{\{(.+?)\}\}/g
};

/* ---- Begin integration of Underscore template engine with Knockout. Could go in a separate file of course. ---- */
    ko.underscoreTemplateEngine = function () { }
    ko.underscoreTemplateEngine.prototype = ko.utils.extend(new ko.templateEngine(), {
        renderTemplateSource: function (templateSource, bindingContext, options) {
            // Precompile and cache the templates for efficiency
            var precompiled = templateSource['data']('precompiled');
            if (!precompiled) {
                precompiled = _.template("{{ with($data) { }} " + templateSource.text() + " {{ } }}");
                templateSource['data']('precompiled', precompiled);
            }
            // Run the template and parse its output into an array of DOM elements
            var renderedMarkup = precompiled(bindingContext).replace(/\s+/g, " ");
            return ko.utils.parseHtmlFragment(renderedMarkup);
        },
        createJavaScriptEvaluatorBlock: function(script) {
            return "{{ " + script + " }}";
        }
    });
    ko.setTemplateEngine(new ko.underscoreTemplateEngine());
/* ---- End integration of Underscore template engine with Knockout ---- */

var viewModel = {
    model: ko.observableArray([
        { Value: '1', IsChecked: 1 },
        { Value: '2', IsChecked: 0 },
        { Value: '3', IsChecked: 1 },
        { Value: '4', IsChecked: 0 },
        { Value: '5', IsChecked: 1 },
    ])        
};

ko.applyBindings(viewModel);

PS:ただし、HTMLレイアウトにテーブルを使用することは避けたほうがよいでしょう。あなたの例は、はるかにクリーンなコードでインラインブロック要素を使用してレンダリングできます。

于 2012-12-17T23:51:37.093 に答える