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);
};
agradl
la source
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()

RP Niemeyer
la source
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>
Dave
la source
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/

Jhankar Mahbub
la source
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>
Michael Best
la source
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 = "";
    }
};
Yogev Smila
la source
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
-->
THX-1138
la source
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.

ccastanedag
la source
-1

Peut également utiliser caché comme ceci:

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