Magento 2: ¿Qué es una etiqueta `<each />`?

13

Por lo que puedo decir, cuando ve una cuadrícula en el backend de Magento, la siguiente plantilla KnockoutJS "cargada sobre XHR" es lo que comienza a representar las cosas

File: vendor/magento//module-ui/view/base/web/templates/collection.html
URL:  http://magento.example.xom/pub/static/adminhtml/Magento/backend/en_US/Magento_Ui/templates/collection.html
<each args="data: elems, as: 'element'">
    <render if="hasTemplate()"/>
</each>

Sin embargo, estoy un poco perdido en cuanto a lo que son la <each/>etiqueta y la <render/>etiqueta. No son (¿o no parecen ser?) Una parte del inventario KnockoutJS.

Sé que es posible agregar etiquetas personalizadas a KnockoutJS a través de componentes , pero no veo ningún lugar obvio donde un componente nombrado eacho renderagregado a KnockoutJS.

Por lo tanto, no estoy seguro de si estos son componentes registrados en algún lugar que no conozco, o alguna otra personalización que Magento haya hecho a KnockoutJS que permita etiquetas personalizadas, o algo completamente diferente.

Nota: No estoy completamente en la oscuridad aquí: entiendo que <each/>probablemente esté iterando sobre cada componente de interfaz de usuario secundario representado en el JSON y representando su plantilla (si esa plantilla existe).

Lo que no tengo claro es cómo se implementan estas etiquetas. Quiero ver dónde se implementan para poder depurar cómo se enlazan los datos y también entender el mecanismo que Magento está utilizando para crear estas etiquetas en caso de que haya otras.

Alan Storm
fuente

Respuestas:

10

Como Raphael insinuó, resulta que cuando Magento descarga sus plantillas KnockoutJS a través de una solicitud XHR (es decir, ajax), también las pasa a través de algunas rutinas de análisis personalizadas que buscan una serie de etiquetas y atributos personalizados

Este análisis personalizado lo realiza el Magento_Ui/js/lib/knockout/template/renderermódulo RequireJS. El código fuente de este módulo establece una serie de etiquetas y atributos predeterminados para buscar. También hay otros módulos que pueden agregar etiquetas y atributos adicionales a este procesador. Por ejemplo, lo siguiente

#File: vendor/magento/module-ui/view/base/web/js/lib/knockout/bindings/scope.js
renderer
    .addNode('scope')
    .addAttribute('scope', {
        name: 'ko-scope'
    });

agregará la <scope/>etiqueta y el scopeatributo ( <div scope="...">) a la lista de atributos analizables.

Es parece como la idea básica consiste en traducir las siguientes etiquetas y atributos en Knockout "tagless" bloques plantilla nativos. Por ejemplo, la siguiente plantilla de Magento KnockoutJS

<each args="data: elems, as: 'element'">
    <render if="hasTemplate()"/>
</each>

Se traduce en el siguiente código nativo KnockoutJS

<!-- ko foreach: {data: elems, as: 'element'} -->
    <!-- ko if: hasTemplate() --><!-- ko template: getTemplate() --><!-- /ko --><!-- /ko -->
<!-- /ko -->

Las reglas exactas de esta traducción aún no están claras para mí: el código en Magento_Ui/js/lib/knockout/template/rendereres un poco indirecto, y parece que pueden cambiar de etiqueta a etiqueta, de atributo a atributo.

He creado el siguiente fragmento de código que puede descargar una plantilla de Magento KnockoutJS y traducirlo al código nativo de KnockoutJS.

jQuery.get('http://magento-2-1-0.dev/static/adminhtml/Magento/backend/en_US/Magento_Ui/templates/collection.html', function(result){
    var renderer = requirejs('Magento_Ui/js/lib/knockout/template/renderer')
    var fragment = document.createDocumentFragment();
    $(fragment).append(result);

    //fragment is passed by reference, modified
    renderer.normalize(fragment);
    var string = new XMLSerializer().serializeToString(fragment);
    console.log(string);    
})

En cuanto a por qué Magento podría hacer esto, supongo que querrá algún tipo de resaltado de sintaxis y legibilidad para la plantilla de comentarios de KnockoutJS, pero nunca descarte más razones de Mallory .

Alan Storm
fuente
2

Ambas etiquetas se implementan en app/code/Magento/Ui/view/base/web/js/lib/knockout/template/renderer.js, aunque no estoy seguro de entender exactamente cómo se implementan:

_.extend(preset.nodes, {
    foreach: {
        name: 'each'
    },

    /**
     * Custom 'render' node handler function.
     * Replaces node with knockout's 'ko template:' comment tag.
     *
     * @param {HTMLElement} node - Element to be processed.
     * @param {String} data - Data specified in 'args' attribute of a node.
     */
    render: function (node, data) {
        data = data || 'getTemplate()';
        data = renderer.wrapArgs(data);

        renderer.wrapNode(node, 'template', data);
        $(node).replaceWith(node.childNodes);
    }
});
Raphael en Digital Pianism
fuente