Est-il possible de lier des données visible à la négation («!») D'une propriété booléenne ViewModel?


162

Je voudrais utiliser une propriété sur mon ViewModel pour basculer l'icône à afficher sans créer une propriété calculée distincte de l'inverse. Est-ce possible?

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

My ViewModel a une propriété périodes qui est un tableau de mois, comme ceci:

var month = function() {
    this.charted = ko.observable(false);
};

3
@Niko: Ce n'est pas vraiment une question en double. L'OP de la question que vous faites référence à savait déjà que il est possible de lier des données-la négation d'une observable, mais se demande pourquoi il a besoin d'être appelé comme une fonction. Le PO de cette question ici ne savait pas comment faire cela en premier lieu et n'a évidemment pas trouvé cette autre question. Je suis content d'avoir trouvé cette question ici - qui est principalement grâce à son titre descriptif.
Oliver

Réponses:


281

Lorsque vous utilisez une observable dans une expression, vous devez y accéder en tant que fonction telle que:

visible: !charted()


33
Peut-être devrions-nous créer une liaison cachée :) Nous avons activé et désactivé.
John Papa

La documentation est-elle en désaccord avec cela, ou est-ce que je comprends complètement cette page: knockoutjs.com/documentation/css-binding.html
Devil's Advocate

Peu importe, je suppose que "isSevere" n'est pas une propriété observable mais une propriété ancienne, d'où ma confusion.
Devil's Advocate

3
Lorsque vous utilisez! Charted, vous obtenez! [Function]. [Function] est vrai,! [Function] devient faux et sera toujours faux si vous utilisez cette syntaxe. jsfiddle.net/datashaman/E58u2/3
datashaman

1
Ils ont en fait ajouté la hiddenliaison dans la v3.5.0
Grin

53

Je suis d'accord avec le commentaire de John Papa selon lequel il devrait y avoir une hiddenreliure intégrée . Il y a deux avantages à une hiddenliaison dédiée :

  1. Syntaxe plus simple, c'est-à-dire. hidden: chartedau lieu de visible: !charted().
  2. Moins de ressources, puisque Knockout peut observer l'observable charteddirectement, plutôt que de créer un computedpour observer !charted().

C'est assez simple pour créer une hiddenliaison, cependant, comme ceci:

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

Vous pouvez l'utiliser comme la visibleliaison intégrée :

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

9
cela n'a pas fonctionné pour moi sans retourreturn !ko.utils.unwrapObservable(valueAccessor());
Mehmet Ataş

Merci @ MehmetAtaş - J'ai corrigé la hiddenreliure par votre commentaire. (BTW, j'utilisais CoffeeScript dans mon projet au moment où j'ai publié ceci à l'origine. La syntaxe de CoffeeScript ne rend pas évident quand un retour est intentionnel.)
Dave

9

C'est peu déroutant, comme tu dois le faire

visible:!showMe()

alors je l'ai fait

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

mon modèle est

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

Enregistrer violon http://jsfiddle.net/khanSharp/bgdbm/


4

Vous pouvez utiliser ma liaison commutateur / boîtier , qui comprend case.visibleet 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>

Vous pourriez aussi l'avoir comme

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

Je viens de réaliser que c'est une vieille question, mais j'espère que cela pourrait être utile à quelqu'un.
Michael Best

1

Afin de rendre la liaison consciente des modifications apportées à la propriété, j'ai copié le gestionnaire de liaison visible et je l'ai inversé:

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 = "";
    }
};

0

Avertissement: cette solution est uniquement à des fins de divertissement.

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

0

J'avais le même problème sur la façon d'utiliser un opposé d'une observable booléenne. J'ai trouvé une solution simple:

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

};

Maintenant, sur votre HTML, vous devriez le faire

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

Lorsque le programme démarre, seul "Text1" est visible car "false === false is TRUE" et Text2 n'est pas visible.

Disons que nous avons un bouton qui invoque l'événement rassemblerPlacesData on click. Maintenant Text1 ne sera plus visible car "true === false is FALSE" et Text 2 ne sera visible que.

Une autre solution possible pourrait être l'utilisation d'observables calculés, mais je pense que c'est une solution trop compliquée pour un problème si simple.


-1

Peut également utiliser caché comme ceci:

 <div data-bind="hidden: isString">
                            <input type="text" class="form-control" data-bind="value: settingValue" />
                        </div>
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.