Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
678 views
in Technique[技术] by (71.8m points)

javascript - Can Knockout.js bindings apply to container tags AND descendants both?

Let me setup the question with a simple case.

I have an HTML table, the rows of which are controlled by an observableArray. It works great.

If the observableArray has zero elements in it however, I want a single row to say so. I tried this markup, which "kind of" works:

<tbody data-bind="if: $root.data.contacts().length == 0">
    <tr>
        <td>There are no contacts specified yet.</td>
    </tr>
</tbody>

<tbody data-bind="foreach: $root.data.contacts">
        SNIP - a tbody with the rows is here when elements > zero
</tbody>

When I say "kind of", I mean VISIBLY. It really does show up at zero elements and really does go away at > zero elements like what you would expect. However when you open the DOM inspector (dev tools) and look at the DOM in memory, you find that there are TWO tbody sections, not one. Now one tbody is always empty of course, but two tbody tags is not HTML5 correct, so this must be fixed this is not the desired markup.

Being a Knockout newbie, I tried to fix this problem with a virtual element:

<!-- ko if: $root.data.contacts().length == 0 -->
<tbody>
    <tr>
        <td>There are no contacts specified yet.</td>
    </tr>
</tbody>
<!-- /ko -->

Unfortunately this doesn't work for our build process: we minify HTML prior to compression and comments get eliminated.

I was under the impression that KO bindings applied to the CONTAINER ELEMENT ITSELF as well as descendants, but this seems to not be so. Is there a way to tell KO to apply to container elements as well as children, or do I need to change the markup in some way OTHER THAN a virtual container?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Like you, my first choice would be virtual tags for an if binding. But since that's not an option, how about swappable templates?

var vm = {
  contacts: ko.observableArray()
};

ko.applyBindings(vm);

setTimeout(function() {
  vm.contacts(['One', 'Two', 'Three']);
}, 2500);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<template id="empty-body">
  <tbody>
    <tr>
      <td>There are no contacts specified yet.</td>
    </tr>
  </tbody>
</template>
<template id="normal-body">
  <tbody data-bind="foreach: contacts">
    <tr>
      <td data-bind="text:$data"></td>
    </tr>
  </tbody>
</template>
<table data-bind="template: contacts().length === 0 ? 'empty-body' : 'normal-body'"></table>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...