¿Es posible vincular datos visibles a la negación ("!") De una propiedad booleana de ViewModel?

162

Me gustaría usar una propiedad en mi ViewModel para alternar qué icono mostrar sin crear una propiedad computada separada de la inversa. es posible?

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

Mi ViewModel tiene períodos de propiedad que son una variedad de meses, como este:

var month = function() {
    this.charted = ko.observable(false);
};
agradl
fuente
3
@Niko: No es realmente una pregunta duplicada. El OP de la pregunta a la que se refiere ya sabía que es posible vincular datos a la negación de un observable, pero se pregunta por qué debe llamarse como una función. El OP de esta pregunta aquí no sabía cómo hacerlo en primer lugar y obviamente no encontró esa otra pregunta. Me alegro de haber encontrado esta pregunta aquí, que se debe principalmente a su título descriptivo.
Oliver

Respuestas:

281

Al usar un observable en una expresión, debe acceder a él como una función como:

visible: !charted()

RP Niemeyer
fuente
33
Tal vez deberíamos hacer un enlace oculto :) Tenemos habilitar y deshabilitar.
John Papa
¿La documentación no está de acuerdo con esto, o estoy entendiendo completamente mal esta página: knockoutjs.com/documentation/css-binding.html
Devil's Advocate
No importa, supongo que "isSevere" no es una propiedad observable sino una propiedad antigua, por lo tanto, mi confusión.
Abogado del Diablo
3
Al usar! Charted, obtienes! [Función]. [Función] es veraz,! [Función] se vuelve falsa y siempre será falsa si usa esa sintaxis. jsfiddle.net/datashaman/E58u2/3
datashaman
1
En realidad, agregaron hiddenenlace en v3.5.0
Grin
53

Estoy de acuerdo con el comentario de John Papa de que debería haber un hiddenenlace incorporado . Hay dos beneficios para un hiddenenlace dedicado :

  1. Sintaxis más simple, es decir. hidden: charteden vez devisible: !charted() .
  2. Menos recursos, ya que Knockout puede observar lo observable charteddirectamente, en lugar de crear un computedpara observar !charted().

Sin hiddenembargo, es lo suficientemente simple como para crear un enlace, como este:

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

Puede usarlo como el visibleenlace incorporado :

<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
fuente
9
esto no funcionó para mí sin retornoreturn !ko.utils.unwrapObservable(valueAccessor());
Mehmet Ataş
Gracias @ MehmetAtaş - Corregí el hiddenenlace por su comentario. (Por cierto, estaba usando CoffeeScript en mi proyecto en el momento en que publiqué esto originalmente. La sintaxis de CoffeeScript no lo hace obvio cuando un retorno es intencional)
Dave
9

Es un poco confuso, como tienes que hacer

visible:!showMe()

Así que lo hice

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

mi modelo es

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

Comprobar el violín http://jsfiddle.net/khanSharp/bgdbm/

Jhankar Mahbub
fuente
4

Podrías usar mi encuadernación de interruptor / caja , que incluye case.visibley 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>

También podrías tenerlo 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
fuente
Me acabo de dar cuenta de que esta es una vieja pregunta, pero espero que esto pueda ser útil para alguien.
Michael Best
1

Para que el enlace sea consciente de los cambios en la propiedad, copié el controlador de enlace visible y lo invertí:

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

Descargo de responsabilidad: esta solución es solo para fines de entretenimiento.

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

Estaba teniendo el mismo problema sobre cómo usar un opuesto de un observable booleano. He encontrado una solución 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);

};

Ahora en tu HTML deberías hacer esto

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

Cuando se inicia el programa, solo "Text1" es visible porque "false === false es TRUE" y Text2 no es visible.

Digamos que tenemos un botón que invoca el evento collectPlacesData al hacer clic. Ahora Text1 no estará visible porque "true === false es FALSE" y Text 2 solo estará visible.

Otra posible solución podría ser el uso de observables computados, pero creo que es una solución demasiado complicada para un problema tan simple.

ccastanedag
fuente
-1

También se puede usar oculto así:

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