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

95

Я постоянно использую эту идиому в шаблонах 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>
Дженсен Чинг
источник
Любой, кто смотрит на это, может захотеть
Брайан М. Хант

Ответы:

64

Есть несколько способов обработки этого типа кода.

  • с комбинацией 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Функция может жить там , где, но будет дан элемент ($ данных) в качестве первого аргумента , и возвратит имя шаблона для использования.

Р.П. Нимейер
источник
странно, мой HTML не отображается. Также только что заметил, что Майкл дал примерно такой же ответ.
RP Niemeyer
Спасибо за исчерпывающий список вариантов. Думаю, мой оригинальный стиль кода подходит для простых случаев. Я проверю другие варианты, когда возникнет необходимость.
Jensen Ching
есть ли способ еще больше настроить шаблон, например "template: data, proppertyName: 'email'" и в шаблоне data-bind = "text: $ data [propertyName]".
Онур Топал
@OnurTOPAL - да, если у вас есть переменная propertyName, вы можете динамически определять имя шаблона.
RP Niemeyer
44

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

<!-- 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>

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

<!-- 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 -->
Майкл Бест
источник
Спасибо. Я буду помнить о плагине switch / case, когда в этом возникнет необходимость.
Jensen Ching
2
Хороший плагин, который у вас есть! Обязательно воспользуюсь этим.
Kukks
Именованные шаблоны отлично работают, и они поддерживают сценарии типа if elseif elseif else путем вложения терниарного оператора.
4

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

    <!-- ko with: $data.DoSomePerformanceCriticalWork($data.SomeParameter()) -->
        <!-- ko if: $data.Condition() -->
           ... some markup ...
        <!-- /ko -->
        <!-- ko ifnot: $data.Condition() -->
           ... some markup ...
        <!-- /ko -->
    <!-- /ko -->
Дмитрий Комин
источник
1

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

Брайан М. Хант
источник