Cómo compartir observables Knockout JS entre componentes de la interfaz de usuario

12

Entiendo cómo usar imports: {}yexports: {} compartir las propiedades de los componentes de una interfaz de usuario, como:

defaults: {
    exports: {
        shouldShowMessage: '${$.component}'
    }
}

Que devuelve el nombre del componente en las exportaciones.

ingrese la descripción de la imagen aquí

Pero cuando trato de exportar un Knockout observable, siempre está indefinido:

defaults: {
    exports: {
        shouldShowMessage: '${$.shouldShowMessage}'
    }
}

...

setupKoBindings: function() {
    this.shouldShowMessage = ko.observable('Testing');
}

ingrese la descripción de la imagen aquí

Como solución alternativa, voy a crear un modelo de almacenamiento como se explica aquí, pero preferiría usar las importaciones y exportaciones.

Ben Crook
fuente

Respuestas:

12

Los valores del objeto de exportación deben resolverse en un nombre y una propiedad de una instancia de UiComponent, separados por un ':', por ejemplo checkout.cart.total:title.
El nombre del objetivo de exportación debe incluir el "espacio de nombres" del componente de la interfaz de usuario.

En su ejemplo, establece el valor en una cadena, que se resuelve en una propiedad del componente Ui que es la fuente de exportación. La exportación no está definida cuando la inspecciona porque ese no es un objetivo de exportación válido.

Aquí hay un ejemplo que funciona:

defaults: {
    exportTarget: "foo.bar",
    exportTargetProperty: "showMessage",

    tracks: {
        shouldShowMessage: true
    },

    exports: {
        shouldShowMessage: '${$.exportTarget}:${$.exportTargetProperty}'
    }
}
...

Lo anterior copiará el valor de la shouldShowMessagepropiedad en la propiedad showMessagede un UiComponent con el nombre completo foo.barcada vez que cambie el valor.
Tenga en cuenta que esto no hará que la propiedad de destino sea también un KO observable automáticamente. Eso tiene que declararse explícitamente, si los cambios de valor desencadenan que KO vuelva a generar nodos DOM que acceden a esa propiedad.

Por cierto, agregar shouldShowMessageal tracksobjeto lo hará un ko-es5 observable automáticamente. Usar un trabajo literal ko.observable()también.

En el ejemplo anterior, exportTargety exportTargetPropertyse configuran en defaults. También podrían especificarse como parte de las opciones de UiComponent en el JSON, lo que generalmente tiene más sentido, ya que allí es donde se define la jerarquía de UiComponent, incluidos los nombres de UiComponent.

Finalmente, me gustaría señalar que personalmente creo que su solución usando un objeto de valor para pasar el valor al otro componente de la interfaz de usuario es mejor que usar exportaciones o importaciones. En mi experiencia, mantener el estado compartido en el DOM o en UiComponents es una receta para spaghetti OOP en todos los casos, excepto en los más simples.

Vinaí
fuente
Excelente explicación, gracias @Vinai! Lo intentaré cuando tenga tiempo y lo marcaré como aceptado si funciona.
Ben Crook
Me he encontrado con algunos problemas al usar tracks, suscribirse manualmente a observables ya no funciona this.shouldShowMessage.subscribe is not a functioncuando se usa. this.shouldShowMessage.subscribe(function() { ... }); Funciona bien al configurar observables de otra manera. Parece que me falta un paso o tracksno crea un observable de la misma manera.
Ben Crook
Tienes razón, las propiedades ya no son observables ko regulares, solo pares ES5 getter / setter. Si desea acceder a la función observable original, puede inyectar ko y usar ko.getObservable(this, 'shouldShowMessage').subscribe(function(newValue) { ...});(el primer argumento es viewmodel ( this), el segundo el nombre de la propiedad rastreada. Más información aquí: github.com/SteveSanderson/knockout-es5
Vinai
Ah, eso tiene sentido, eres el mejor <3
Ben Crook
1
Después de jugar con las importaciones y exportaciones y aún fallando, acepto que este es un código de espagueti, me di por vencido y me quedaré con las suscripciones manuales y un modelo de almacenamiento.
Ben Crook