【问题标题】:How to render tr conditionally in knockout.js foreach binding如何在 knockout.js foreach 绑定中有条件地渲染 tr
【发布时间】:2012-12-17 22:48:24
【问题描述】:

我想使用淘汰赛动态呈现行和列。这个想法是我想用一些单元格填充每一行,并在需要时动态添加更多行。 让我们假设单元格总数等于 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,但这需要我的模型从一维变为二维,这看起来很奇怪。

【问题讨论】:

  • 您确定要为此使用 HTML 表格吗?如果您有一个平面项目列表作为您的数据,您是否可以不只是将它们呈现为 div 并使用 CSS 让它们在一个容器内自然流动,跨越 4 个?
  • 是的,它的表格数据和表格用于使用 div 显示表格数据将是解决方法而不是解决方案

标签: javascript knockout.js template-engine


【解决方案1】:

添加另一个计算属性,将数据结构化为行:

<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);
});

【讨论】:

    【解决方案2】:

    您的语法不能与淘汰赛默认模板引擎一起使用,因为它使用 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);
    

    P.S.:但更好avoid using tables for html layout。您的示例可以使用具有更简洁代码的内联块元素呈现。

    【讨论】:

    • +1 用于 DOM 与文本模板,但我不想使用其他模板引擎
    猜你喜欢
    • 2015-10-05
    • 2018-09-10
    • 2019-01-13
    • 2013-06-16
    • 1970-01-01
    • 2021-11-19
    • 2011-05-21
    • 2012-09-16
    • 2021-01-08
    相关资源
    最近更新 更多