Como modelar estruturas If-Else em visualizações vinculadas a dados?

95

Eu constantemente me pego usando este idioma em modelos HTML baseados em 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 -->

Existe uma maneira melhor / mais limpa de fazer condicionais em KO, ou há uma abordagem melhor do que apenas usar construções if-else tradicionais?

Além disso, gostaria apenas de salientar que algumas versões do Internet Explorer (IE 8/9) não analisam o exemplo acima corretamente. Por favor, veja esta pergunta do SO para mais informações. O resumo rápido é: não use comentários (ligações virtuais) dentro de tags de tabela para oferecer suporte ao IE. Em tbodyvez disso, use :

<tbody data-bind="if: display"><tr><td>hello</td></tr></tbody>
Jensen Ching
fonte
Quem estiver
Brian M. Hunt,

Respostas:

64

Existem algumas maneiras diferentes de lidar com esse tipo de código.

  • com uma combinação if / ifnot como você está agora. Isso funciona bem e não é muito prolixo.

  • A vinculação de switch / case de Michael Best ( https://github.com/mbest/knockout-switch-case ) é bastante flexível e pode permitir que você lide facilmente com isso e com outros mais complicados (mais estados do que verdadeiro / falso).

  • Outra opção é usar modelos dinâmicos. Você vincularia uma área a um ou mais modelos com o nome do modelo sendo usado com base em um observável. Aqui está um post que escrevi sobre esse tópico há algum tempo: http://www.knockmeout.net/2011/03/quick-tip-dynamically-changing.html . Em seu cenário, pode ser assim:

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

A getCellTemplatefunção poderia residir em qualquer lugar, mas receberia o item ($ data) como o primeiro argumento e retornaria o nome do modelo a ser usado.

RP Niemeyer
fonte
estranho, meu HTML não vai aparecer. Também acabei de notar que Michael deu praticamente a mesma resposta.
RP Niemeyer
Obrigado por uma lista abrangente de opções. Acho que meu estilo de código original funciona para casos simples. Vou verificar as outras opções quando for necessário.
Jensen Ching
existe uma maneira de personalizar o template ainda mais, como "template: data, proppertyName: 'email'" e no template data-bind = "text: $ data [propertyName]".
Onur Topal
@OnurTOPAL - sim, contanto que você tenha uma variável propertyName, você pode determinar dinamicamente o nome do modelo.
RP Niemeyer
44

Uma abordagem é usar modelos nomeados (que podem suportar a passagem de argumentos):

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

Outra opção é usar meu plug-in switch / case , que funcionaria assim:

<!-- 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 -->
Michael Best
fonte
Obrigado. Vou manter o plug-in switch / case em mente para quando for necessário.
Jensen Ching
2
Belo plugin você tem aí! Vou usar este com certeza.
Kukks de
Os modelos nomeados funcionam muito bem e oferecem suporte a cenários de tipo if elseif elseif aninhando o operador terniário.
4

Para evitar o recálculo da ligação knockout ao usar a combinação de if: / ifnot: você pode usá-los em conjunto com a construção 'with:'

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

Agora existe também o knockout-elsebinding / plugin (que escrevi para resolver esse problema).

Brian M. Hunt
fonte