官术网_书友最值得收藏!

Control flow bindings

So far, we have looked at one-way and two-way bindings that set or sync data with an attribute on an HTML element. There is a different kind of binding that Knockout uses for modifying the DOM by adding or removing nodes. These are the control flow bindings, and they include foreach, if, with, and template.

All of the control flow bindings work by actually removing their content from the DOM and creating an in-memory template from it. This template is used to add and remove the content as necessary.

Control flow bindings (except if) also introduce a binding context hierarchy. Your root binding context is the viewmodel passed to ko.applyBindings. The data-bind attributes have access to properties in the current context. Control flow bindings (other than if) create a child-binding context, meaning that data-bind attributes inside the control flow binding's template have access to the properties of their context and not the root context. Bindings inside a child context have access to special properties to allow them to navigate the context hierarchy. The most commonly used are:

  • $parent: This accesses the binding context of the immediate parent. In this example, group and $parent.group refer to the same property because $parent accesses the context outside of the person:
    <span data-bind="text: group"></span>
    <div data-bind="with: person">
      <span data-bind="text: name"></span>
    <span data-bind="text: $parent.group"></span>
      </div>
  • $parents[n]: This is an array of parent contexts. The $parents[0] array is same as $parent.
  • $root: This is the root viewmodel, the highest context in the hierarchy.
  • $data: This is the current viewmodel, useful inside foreach loops.

    Note

    For a complete list of context properties, see the Knockout documentation for them at http://knockoutjs.com/documentation/binding-context.html.

The if binding

The if binding takes a value or expression to evaluate and only renders the contained template when the value or expression is truthy (in the JavaScript sense). If the expression is falsy, the template is removed from the DOM. When the expression becomes true, the template is recreated and any contained data-bind attributes are reapplied. The if binding does not create a new binding context:

<div data-bind="if: isAdmin">
  <span data-bind="text: user.username"></span>
  <button data-bind="click: deleteUser">Delete</button>
</div>

This div would be empty when isAdmin is false or null. If the value of isAdmin is updated, the binding will re-evaluate and add or remove the template as necessary.

There is also an ifnot binding that just inverts the expression. It's useful if you want to still use a property reference without needing to add a bang and parentheses. The following two lines are equivalent:

<div data-bind="if: !isAdmin()" >
<div data-bind="ifnot: isAdmin">

The parentheses are needed in the first example because it is an expression, not a property name. They are not needed in the second example because it is a simple property reference.

The with binding

The with binding creates a new binding context using the supplied value, which causes bindings inside the bound element to be scoped to the new context. These two snippets are functionally similar:

<div>
  First Name:
<span data-bind="text: selectedPerson().firstName"></span>
  Last Name:
<span data-bind="text: selectedPerson().lastName"></span>
</div>

<div data-bind="with: selectedPerson">
  First Name:
<span data-bind="text: firstName"></span>
  Last Name:
<span data-bind="text: lastName"></span>
</div>

While saving a few keystrokes and keeping your bindings easier to read is nice, the real benefit of the with binding is that it is an implicit if binding. If the value is null or undefined, the content of the HTML element will be removed from the DOM. In the cases where this is possible, it saves you from the need to make null checks for each descendant binding.

The foreach binding

The foreach binding creates an implicit template using the contents of the HTML element and repeats that template for every element in the array.

This viewmodel contains a list of people we need to render:

var viewmodel = {
  people: [{name: 'Tim'}, {name: 'Justin}, {name: 'Mark'}]
}

With this binding, we create an implicit template for the li element:

<ul data-bind="foreach: people">
  <li data-bind="text: name"></li>
</ul>

This binding produces the following HTML:

<ul>
  <li>Tim</li>
  <li>Justin</li>
  <li>Mark</li>
</ul>

The thing to note here is that the li element is binding against name, which is the property of a person. Inside the foreach binding, the binding context is the child element. If you need to refer to the child itself, you can either use $data or supply an alias to the foreach binding.

The $data option is useful when the array only contains primitives that you want to bind against:

var viewmodel = {
  people: ['Tim', 'Justin, 'Mark']
}
...
<ul data-bind="foreach: people">
  <li data-bind="text: $data"></li>
</ul>

The alias option can clean up your code, but it is particularly useful when you have a nested context and want to refer to the parent. Refer to the following code:

<ul data-bind="foreach: { data: categories, as: 'category' }">
    <li>
        <ul data-bind="foreach: { data: items, as: 'item' }">
          <li>
            <span data-bind="text: category.name"></span>:
            <span data-bind="text: item"></span>
          </li>
         </ul>
    </li>
</ul>

This can be achieved with $parent, of course, but it is more legible when using an alias.

主站蜘蛛池模板: 城口县| 崇礼县| 沂水县| 娄烦县| 巴彦县| 闽侯县| 株洲县| 沂南县| 红桥区| 晴隆县| 濮阳市| 徐汇区| 抚宁县| 读书| 五家渠市| 敦煌市| 勃利县| 肃宁县| 漯河市| 越西县| 石家庄市| 思南县| 霸州市| 五常市| 安徽省| 三台县| 霞浦县| 平顺县| 怀集县| 雷山县| 若羌县| 邹平县| 昂仁县| 旬阳县| 梧州市| 陇川县| 吴旗县| 安西县| 独山县| 巴塘县| 乌什县|