¿Para qué son los valores predeterminados de importación / exportación en un objeto uiElement?

8

En muchos de los constructores de modelos de vista de elemento UI de Magento 2, la defaultsmatriz tendrá una propiedad importso exports.

return Collection.extend({
    defaults: {
        //...
        imports: {
            rows: '${ $.provider }:data.items'
        },

return Insert.extend({
    defaults: {
        //...
        exports: {
            externalFiltersModifier: '${ $.externalProvider }:params.filters_modifier'
        },

Mirando la fuente del uiElementmódulo,

#File: vendor/magento/module-ui/view/base/web/js/lib/core/element/element.js
    initLinks: function () {
        return this.setListeners(this.listens)
                   .setLinks(this.links, 'imports')
                   .setLinks(this.links, 'exports')
                   .setLinks(this.exports, 'exports')
                   .setLinks(this.imports, 'imports');
    },

Estas importaciones / exportaciones parecen tener algo que ver con "vincular" información entre objetos cuando se instancia un objeto. Sin embargo, no está claro cómo funciona esta vinculación (¿basado en uiRegistry?) O cuál es la sintaxis de las cadenas ${ $.provider }:data.items. Está claro que estas cadenas usan literales de plantilla que se expanden en algo como

foo_bar:data.items

Pero el significado de esta cadena final sigue siendo misterioso.

¿Alguien sabe cómo funcionan las propiedades de importación / exportación de estos objetos?

Alan Storm
fuente
No publicaré una respuesta ya que en realidad no los he usado, pero los devdocs dan un poco más de información: devdocs.magento.com/guides/v2.1/ui-components/…
Vinai

Respuestas:

21

Estas propiedades permiten que los componentes se conecten para que puedan interactuar entre sí. El principio es algo simple: importar (tomar) un valor de otro componente o exportar (enviar) un valor a un componente diferente o hacer ambas cosas.


Nota: para mantener la claridad en esta respuesta, un "componente" es un objeto Javascript devuelto por RequireJS, tiene un nombre específico y se puede acceder por ese nombre a través de UIRegistry.

Además, todos los ejemplos a continuación estarían dentro de la defaults: {}propiedad del componente.


Con el principio establecido, comencemos con lo que considero el concepto más fácil:

Importaciones

Esta propiedad toma un valor de otro componente y lo asigna a la propiedad especificada. En el siguiente ejemplo, declaramos una importación:

imports: {
    message: '${ $.provider }:data.message'
}

Cuando Magento inicialice este componente, intentará asignar el valor a la messagepropiedad. Esta propiedad estará disponible en contexto KnockoutJS. Sin embargo, como sabemos , imports.messageprimero evaluará el valor como una expresión literal de plantilla. En este caso, Magento analizará $.providery debería obtener un valor. Si bien eso podría ser cualquier cantidad de cosas, en este ejemplo y de acuerdo con muchos de los casos de uso principales de Magento, es el nombre de un componente que está en el registro de UI. Eso se analizará antes del siguiente paso.

Como la messagepropiedad está en la importspropiedad, se pasará al setLinks()método en uiElement.initLinks(). El setLinks()método está en Magento/Ui/view/base/web/js/lib/core/element/links.js. Allí, recorre todas las propiedades (solo messageaquí) en el objeto que se pasó ( importsen este caso). En esas propiedades, intentará transferir datos de un componente a otro.

La transfer()función es el próximo lugar de interés. Aquí, en el registro se busca el componente que es el "propietario", en el caso de una importación. Este componente es el que actualmente "posee" o tiene los datos y sería el $.providerdel ejemplo anterior. Si se encuentra el componente, procederá a vincular los datos con la setLink()función.

Hay dos cosas notables en ese método: primero, establece un detector de eventos en la propiedad, y segundo, transferirá inmediatamente los datos si se ha enviado el indicador correspondiente. En mis pruebas, siempre pasó el immediateparámetro, por lo que la transferencia ocurrió durante la inicialización. Sin embargo, debido al detector de eventos que se adjuntó en el primer paso, continuará actualizando los valores, si cambian, para que ambos componentes permanezcan sincronizados.

Los datos se configuran en (o, en términos más simples: "devuelto al") componente que tenía la imports: {}propiedad. Como mencioné anteriormente, luego se asigna directamente a la propiedad del componente que lo declaró, esencialmente this.messageen el ejemplo anterior y no this.defaults.imports.message. Como resultado, data-bind="text: messagedebe mostrar el valor devuelto por la data.messagepropiedad del componente vinculado .

Este enfoque le permite definir cuál es el nombre de la propiedad en el componente fuente. En el ejemplo anterior, podría usar en alertMessage: ...lugar de messagecomo el nombre de propiedad de su componente.

Exportaciones

Las exportaciones son lo contrario de imports. Se basan en la misma funcionalidad que las importaciones, pero en lugar de tomar datos de un componente y asignárselos a sí mismo, envía sus propios datos a otro componente. Como resultado, casi todo es lo contrario. Toma este ejemplo:

exports: {
    phoneNumber: '${ $.contactForm }:phone'
}

En este ejemplo, setLinks()toma el valor de la phoneNumberpropiedad de este componente y lo asigna a la phonepropiedad del formulario de contacto . Es lo mismo que declarar explícitamente una phonepropiedad en el $.contactFormcomponente. Sin ninguna configuración particular en el $.contactForm, puede acceder a estos datos directamente. Tal como esto en una plantilla Knockout: data-bind="text: phone.

Enlaces

Finalmente, la linkspropiedad es lo mismo que declarar ambas importsy exportspara la misma propiedad. A primera vista, esto puede parecer una referencia circular. Si bien es así, en ocasiones, esto podría ser útil. Si bien estoy seguro de que hay muchos más casos de uso, el que puedo ver es la capacidad de un componente para manipular datos de otro componente dinámicamente. En este caso, ComponentA es la fuente de algunos datos y los muestra en la página. ComponentB necesita manipular esos datos y, por lo tanto, linksa esa propiedad. Puede mostrar los datos y manipular los datos reales en ComponentA sin extender o cambiar ComponentA.

Sin embargo, una cosa a tener en cuenta es que, por defecto, linksno son una forma de conectar otros dos módulos. En otras palabras, ComponentC no puede linkComponentA a ComponentB. Es un método de sincronización bidireccional de un componente con otro.


La vinculación ( imports, exportsy links) casi siempre puede facilitar también las funciones asignadas a esas propiedades. Me encontré con un comportamiento extraño al crear observables y usar, linkspero en general funcionó bastante bien.

El enlace proporciona valores que están disponibles en el alcance de KnockoutJS y pueden manipularse como lo haría con cualquier otra propiedad. Y, para reiterar claramente: recuerde que el imports, exportsy linksde objetos claves siempre se refieren a propiedades de la componente de corriente (aquel en el que esas propiedades fueron declaradas), mientras que pertenece el valor con el nombre y las propiedades del componente remoto .


En conclusión, Magento utiliza esta funcionalidad de enlace para conectar diferentes componentes entre sí y es una forma de acceder, proporcionar o sincronizar datos con otros componentes.

bassplayer7
fuente
Gran explicación @ bassplayer7 - ¿Tienes algún ejemplo de esto? Entiendo cómo funciona, pero por mi vida, no puedo hacer que dos de mis componentes de IU simples compartan un KO observable.
Ben Crook
@BenCrook, desafortunadamente, no he hecho mucho con esto por un tiempo, así que no tengo uno de inmediato. Por ahora estoy seguro de que lo has descubierto, pero sugiero trabajar con importsy en exportslugar de hacerlo links. He encontrado linksque es más oscuro y quebradizo. Si encontraste un ejemplo, ¿podrías compartir un enlace?
bassplayer7
Intenté y no logré que las importaciones / exportaciones / enlaces funcionaran, Vinai ha respondido la pregunta aquí, aunque aún no he tenido la oportunidad de probarlo.
Ben Crook
Esta información sería excelente en los documentos de desarrollo oficiales. El proceso de UI Cmponent es solo una bestia aterradora.
Nathaniel Rogers