Dentro de un knockout.js expresión de enlace, puedo usar el $data, $primario y $root pseudovariables. ¿Cómo puedo obtener el equivalente de los pseudovariables cuando estoy usando un ko.calculada observable declarado en JavaScript?

Tengo un padre viewmodel con una colección de los niños, y los padres viewmodel tiene un selectedChild observable. Dado que, puedo utilizar el enlace de datos expresiones para añadir una clase CSS a cualquier niño que esté seleccionado actualmente:

<ul data-bind="foreach: children">
    <li data-bind="text: name,
                   css: {selected: $data === $root.selectedChild()},
                   click: $root.selectChild"></li>
</ul>
<script>
vm = {
    selectedChild: ko.observable(),
    children: [{name: 'Bob'}, {name: 'Ned'}],
    selectChild: function(child) { vm.selectedChild(child); }
};
ko.applyBindings(vm);
</script>

Pero mi viewmodels se va a obtener más complejo, y me gustaría «soy seleccionado?» para ser capaz de hacer algo más que añadir una sola clase CSS a un elemento único. Yo realmente quiere hacer un isSelected calculada de la propiedad en el niño viewmodel, por lo que puedo agregar otros calculan las propiedades que dependen de él.

He tratado de escribir código JavaScript que se refiere a $data y $root, sobre la posibilidad de que knockout podría definir esas variables y de alguna manera tienen ellos en el ámbito cuando llama a mi computed evaluador de la función:

{
  name: 'Bob',
  isSelected: ko.computed(function(){ return $data === $root.selectedChild(); })
}

Pero no hubo suerte: dentro de mi evaluador function, tanto $data y $root son undefined.

También he intentado usar ko.contextFor dentro de mi evaluador, ya que da acceso a $data y $root. Por desgracia, dentro de mi evaluador de la función, contextFor también siempre devuelve undefined. (No tenía grandes esperanzas en esta estrategia de todos modos, no está claro qué tan bien knockout sería capaz de rastrear las dependencias, si tuviera que ir detrás de su espalda como este.)

Siempre se podía establecer manualmente una propiedad de cada niño viewmodel que se refiere a los padres viewmodel. Pero sé que knockout tiene la capacidad de hacer esto por mí, y me gustaría al menos explorar si puedo usar sus mecanismos antes de que yo vaya a escribir mi propia.

Parece que no debería ser posible traducir la anterior expresión de enlace a una calculada observable, después de todo, eso es lo que knockout ya no:

El otro truco es que declarativo enlaces son simplemente implementado como se calculan las características observables.

Pero, ¿cómo ir sobre cómo tratar con la $data y $root pseudovariables cuando estoy escribiendo mi propio calculada observable?

InformationsquelleAutor Joe White | 2011-12-27

3 Comentarios

  1. 77

    La pseudovariables sólo están disponibles en el contexto de enlace de datos. El modelo de vista a sí mismo, idealmente, no debe saber o tener cualquiera de las dependencias de la vista en la que se muestre.

    Así, al añadir calculada observables en el modelo de vista, usted no tiene conocimientos de cómo va a ser obligado (como lo que va a ser de $root). Un modelo de vista o parte de un modelo de vista podría incluso estar obligado por separado a múltiples áreas de la página en los diferentes niveles, por lo que el pseudo-variables sería diferente dependiendo del elemento que está empezando.

    Depende de lo que usted está tratando de lograr, pero si usted desea que su hijo tenga un isSelected calculada observable que indica si este objeto es el mismo que el elemento seleccionado en la vista principal del modelo, entonces usted tendrá que encontrar una manera de hacer que los padres al niño.

    Una opción es pasar a los padres en la función de constructor de su hijo. Usted incluso no necesita agregar el puntero al padre como una propiedad de el niño y la puede usar en su calculada observables directamente.

    Algo como:

    var Item = function(name, parent) {
       this.name = ko.observable(name);  
       this.isSelected = ko.computed(function() {
           return this === parent.selectedItem();        
       }, this);
    };
    
    var ViewModel = function() {
       this.selectedItem = ko.observable();
       this.items = ko.observableArray([
           new Item("one", this),
           new Item("two", this),
           new Item("three", this)
           ]);
    };

    Muestra aquí: http://jsfiddle.net/rniemeyer/BuH7N/

    Si todo lo que importa es el estado seleccionado, a continuación, puede modificar para que se pasa una referencia a la selectedItem observables para el niño como constructor: http://jsfiddle.net/rniemeyer/R5MtC/

    Si su padre la vista de modelo se almacena en una variable global, entonces usted podría considerar la posibilidad de no pasar al niño y usando directamente como: http://jsfiddle.net/rniemeyer/3drUL/. Prefiero pasar la referencia para el niño, aunque.

    • gracias por tu segundo ejemplo!
    • ¿cómo se llama a una función en el raíz, así como haciendo click: $root.selectedItem, dentro de la misma unión?
    • por ejemplo , esto no funciona: haga clic en:function() { $matriz.openAlertDialogueEdit($datos)} //$datos parece ser una copia , no el de la referencia real
    • Puede reproducir o demostrar a partir de ese violín? jsfiddle.net/rniemeyer/MweC4. Knockout pasa los datos actuales, como primer argumento, y no es una copia, pero la referencia real.
    • Muy bonita respuesta, mi intuición era hacerlo como usted sugiere, pero yo quería saber lo que otros estaban haciendo, tus argumentos son muy convincentes.
    • Al pasar el ViewModel el Punto, es que, una referencia o una copia de la función? Estoy planeando sobre el uso de este método, sin embargo he de tener, potencialmente, 250~ Elementos y estoy preocupado por el rendimiento de la página, especialmente en un dispositivo móvil.
    • es una referencia a la original

  2. 1

    En mi experiencia, el enfoque en @RP Niemeyer respuesta es bien si Items en vivo para la duración de la aplicación. Pero si no, puede dar lugar a pérdidas de memoria, porque Item‘s calculada observable establece una dependencia inversa de la ViewModel. De nuevo, eso está bien si usted nunca deshacerse de cualquier Item objetos. Pero si intenta hacer para deshacerse de Items no voy a entrar en el recolector de basura porque knockout todavía tendrá que revertir la dependencia de referencia.

    Que podría asegúrese de dispose() de la calculada, tal vez en una limpieza() el método en Item que se llama cuando el elemento desaparece, pero usted tiene que recordar que cada vez que la eliminación de Items.

    Lugar, ¿por qué no hacer Item un poco menos inteligentes y tienen ViewModel decir cuando es seleccionado? Acaba de hacer Item‘s isSelected() un viejo regulares observables y, a continuación, en ViewModel suscribirse a selectedItem y actualización dentro de esa suscripción.

    O, utilice @RP Niemeyer pub/sub solución. (Para ser justos, esta solución surgió después de que su respuesta aquí.) Usted todavía necesita para limpiar, sin embargo, porque crea inversa dependencias, demasiado. Pero al menos hay menos de acoplamiento.

    Véase la respuesta a la mi última pregunta en este mismo tema para obtener más detalles.

Dejar respuesta

Please enter your comment!
Please enter your name here