Как создавать шаблоны If-Else в представлениях, связанных с данными?

Я постоянно нахожу себя использующим эту идиому в HTML-шаблонах на основе KO:

<!-- ko if: isEdit -->
<td><input type="text" name="email" data-bind="value: email" /></td>
<!-- /ko -->
<!-- ko ifnot: isEdit -->
<td data-bind="text: email"></td>
<!-- /ko -->

Есть ли лучший/более чистый способ делать условные выражения в KO, или есть лучший подход, чем просто использование традиционных конструкций if-else?

Кроме того, я хотел бы отметить, что некоторые версии Internet Explorer (IE 8/9) не анализируют приведенный выше пример правильно. См. этот вопрос SO для получения дополнительной информации. Краткое резюме: не используйте комментарии (виртуальные привязки) внутри тегов таблицы для поддержки IE. Вместо этого используйте tbody:

<tbody data-bind="if: display"><tr><td>hello</td></tr></tbody>

Ответ 1

Существует несколько способов, которыми вы можете обращаться с этим типом кода.

  • с комбинацией if/ifnot, как вы сейчас. Это работает отлично и не очень многословно.

  • Майкл Наилучшая привязка переключателя/случая (https://github.com/mbest/knockout-switch-case) довольно гибкая и позволяет вам легко справиться с этим и более сложными (больше состояний, чем true/false).

  • Другой вариант - использовать динамические шаблоны. Вы привязывали бы область к одному или нескольким шаблонам с использованием имени шаблона на основе наблюдаемого. Вот сообщение, которое я написал на эту тему некоторое время назад: http://www.knockmeout.net/2011/03/quick-tip-dynamically-changing.html. В вашем сценарии это может выглядеть так:

<td data-bind="template: $root.getCellTemplate"></td>

<script id="cellEditTmpl" type="text/html">
    <input type="text" name="email" data-bind="value: email" />
</script>

<script id="cellTmpl" type="text/html">
    <span data-bind="text: email"></span>
</script>

Функция getCellTemplate могла бы существовать везде, где бы она ни была, но ей будет присвоен элемент ($ data) в качестве первого аргумента и вернет имя используемого шаблона.

Ответ 2

Один из подходов - использовать именованные шаблоны (которые могут поддерживать передающие аргументы):

<!-- ko template: isEdit() ? 'emailEdit' : 'emailDisplay' --><!-- /ko -->
<script id="emailEdit" type="text/html">
    <td><input type="text" name="email" data-bind="value: email" /></td>
</script>
<script id="emailDisplay" type="text/html">
    <td data-bind="text: email"></td>
</script>

Другим вариантом является использование плагина переключения/случая, который будет работать следующим образом:

<!-- ko switch -->
    <!-- ko case: isEdit -->
        <td><input type="text" name="email" data-bind="value: email" /></td>
    <!-- /ko -->
    <!-- ko case: $else -->
        <td data-bind="text: email"></td>
    <!-- /ko -->
<!-- /ko -->

Ответ 3

Чтобы избежать пересчета привязки нокаута при использовании комбинации if:/ifnot: вы можете использовать их в сочетании с конструкцией "with:"

    <!-- ko with: $data.DoSomePerformanceCriticalWork($data.SomeParameter()) -->
        <!-- ko if: $data.Condition() -->
           ... some markup ...
        <!-- /ko -->
        <!-- ko ifnot: $data.Condition() -->
           ... some markup ...
        <!-- /ko -->
    <!-- /ko -->

Ответ 4

Теперь есть и knockout-else binding/plugin (который я написал для решения этой проблемы).