É possível vincular dados visível à negação ("!") De uma propriedade booleana de ViewModel?

162

Gostaria de usar uma propriedade no meu ViewModel para alternar qual ícone exibir sem criar uma propriedade computada separada do inverso. Isso é possível?

<tbody data-bind="foreach: periods">
  <tr>
    <td>
      <i class="icon-search" data-bind="visible: !charted, click: $parent.pie_it"></i>
      <i class="icon-remove" data-bind="visible: charted, click: $parent.pie_it"></i>
    </td>
  </tr>
</tbody>

Meu ViewModel possui períodos de propriedade que são uma matriz de meses, assim:

var month = function() {
    this.charted = ko.observable(false);
};
agradl
fonte
3
@ Niko: Não é realmente uma pergunta duplicada. O OP da pergunta a que você se refere já sabia que é possível vincular dados à negação de um observável, mas se pergunta por que ele precisa ser chamado como uma função. O OP desta pergunta aqui não sabia como fazer isso em primeiro lugar e, obviamente, não encontrou essa outra pergunta. Fico feliz por ter encontrado essa pergunta aqui - que se deve principalmente ao título descritivo.
Oliver

Respostas:

281

Ao usar um observável em uma expressão, você precisa acessá-lo como uma função como:

visible: !charted()

RP Niemeyer
fonte
33
Talvez devêssemos fazer uma ligação oculta :) Ativamos e desativamos.
19412 John Papa
A documentação não concordar com isso, ou estou mal-entendido completamente esta página: knockoutjs.com/documentation/css-binding.html
Advogado do Diabo
Deixa pra lá, acho que "isSevere" não é uma propriedade observável, mas simples e antiga, portanto, minha confusão.
Advogado do Diabo
3
Ao usar! Charted, você está recebendo! [Função]. [Function] é verdadeiro,! [Function] se torna falso e sempre será falso se você usar essa sintaxe. jsfiddle.net/datashaman/E58u2/3
datashaman
1
Na verdade, eles adicionaram a hiddenligação na v3.5.0
Grin
53

Concordo com o comentário de John Papa de que deveria haver uma hiddenligação embutida . Há dois benefícios em uma hiddenligação dedicada :

  1. Sintaxe mais simples, ie. hidden: chartedem vez de visible: !charted().
  2. Menos recursos, já que o Knockout pode observar o observável charteddiretamente, em vez de criar um computedpara observar !charted().

É simples o suficiente para criar uma hiddenligação, porém, assim:

ko.bindingHandlers.hidden = {
  update: function(element, valueAccessor) {
    ko.bindingHandlers.visible.update(element, function() {
      return !ko.utils.unwrapObservable(valueAccessor());
    });
  }
};

Você pode usá-lo exatamente como a visibleligação interna:

<i class="icon-search" data-bind="hidden: charted, click: $parent.pie_it"></i>
<i class="icon-remove" data-bind="visible: charted, click: $parent.pie_it"></i>
Dave
fonte
9
isso não funcionou para mim sem retornoreturn !ko.utils.unwrapObservable(valueAccessor());
Mehmet ATAS
Obrigado @ MehmetAtaş - Corrigi a hiddenligação por seu comentário. (BTW, eu estava usando CoffeeScript no meu projeto no momento que eu postei isso originalmente sintaxe do CoffeeScript não o torna óbvio quando um retorno é intencional..)
Dave
9

É um pouco confuso, como você tem que fazer

visible:!showMe()

então eu fiz

<span data-bind="visible:showMe">Show</span>
<span data-bind="visible:!showMe()">Hide</span>
<label><input type="checkbox" data-bind="checked:showMe"/>toggle</label>​

meu modelo é

var myModel={
    showMe:ko.observable(true)
}
ko.applyBindings(myModel);    

Check-in violino http://jsfiddle.net/khanSharp/bgdbm/

Jhankar Mahbub
fonte
4

Você pode usar minha ligação switch / case , que inclui case.visiblee casenot.visible.

<tbody data-bind="foreach: periods">
    <tr>
        <td data-bind="switch: true">
        <i class="icon-search" data-bind="case.visible: $else, click: $parent.pie_it"></i>
        <i class="icon-remove" data-bind="case.visible: charted, click: $parent.pie_it"></i>
        </td>
    </tr>
</tbody>

Você também pode tê-lo como

        <i class="icon-search" data-bind="casenot.visible: charted, click: $parent.pie_it"></i>
        <i class="icon-remove" data-bind="case.visible: $else, click: $parent.pie_it"></i>
Michael Best
fonte
Acabei de perceber que essa é uma pergunta antiga, mas espero que isso possa ser útil para alguém.
22712 Michael Best
1

Para tornar a ligação ciente das alterações na propriedade, copiei o manipulador de ligação visível e o invertei:

ko.bindingHandlers.hidden = {
    update: function (element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        var isCurrentlyHidden = !(element.style.display == "");
        if (value && !isCurrentlyHidden)
            element.style.display = "none";
        else if ((!value) && isCurrentlyHidden)
            element.style.display = "";
    }
};
Yogev Smila
fonte
0

Isenção de responsabilidade: esta solução é apenas para fins de entretenimento.

ko.extenders.not = function (target) {
    target.not = ko.computed(function () {
        return !target();
    });
};

self.foo = ko.observable(true).extend({ not: null });

<div data-bind="text: foo"></div>     <!-- true -->
<div data-bind="text: foo.not"></div> <!-- false -->

<!-- unfortunately I can't think of a way to be able to use:
    text: foo...not
-->
THX-1138
fonte
0

Eu estava tendo o mesmo problema sobre como usar o oposto de um observável booleano. Eu encontrei uma solução fácil:

var ViewModel = function () {
var self = this;

// When program start, this is set to FALSE
self.isSearchContentValid = ko.observable(false);


self.gatherPlacesData = function () {

   // When user click a button, the value become TRUE
   self.isSearchContentValid(true);

};

Agora no seu HTML você deve fazer isso

<p data-bind = "visible:isSearchContentValid() === false"> Text 1</p>
<p data-bind = "visible:isSearchContentValid"> Text 2</p>

Quando o programa é iniciado, apenas "Text1" fica visível porque "false === false is TRUE" e Text2 não está visível.

Digamos que temos um botão que chama o evento gatherPlacesData on click. Agora o Texto1 não estará visível porque "true === false é FALSE" e o Texto 2 estará visível apenas.

Outra solução possível poderia estar usando o computador observável, mas acho que é uma solução complicada demais para um problema tão simples.

ccastanedag
fonte
-1

Também pode usar oculto assim:

 <div data-bind="hidden: isString">
                            <input type="text" class="form-control" data-bind="value: settingValue" />
                        </div>
Dev-Systematix
fonte