Magento 2: Qu'est-ce qu'une balise `<each />`?

13

Pour autant que je sache, lorsque vous affichez une grille dans le backend de Magento, le modèle KnockoutJS "chargé sur XHR" suivant est ce qui commence à rendre les choses

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>

Cependant - je suis un peu perdu quant à ce que sont l' <each/>étiquette et l' <render/>étiquette. Ils ne font pas partie de KnockoutJS (ou ne semblent pas l'être?).

Je sais qu'il est possible d'ajouter des balises personnalisées à KnockoutJS via des composants , mais je ne vois aucun endroit évident où un composant nommé eachou renderest ajouté à KnockoutJS.

Donc, je ne sais pas s'il s'agit de composants enregistrés quelque part que je ne connais pas, ou d'une autre personnalisation que Magento a apportée à KnockoutJS qui permet des balises personnalisées, ou autre chose entièrement.

Remarque: je ne suis pas complètement dans l'obscurité ici - je comprends que cela <each/>est probablement en train d'itérer sur chaque composant d'interface utilisateur enfant rendu dans le JSON et de rendre son modèle (si ce modèle existe).

Ce que je ne sais pas du tout, c'est comment ces balises sont implémentées. Je veux voir où ils sont implémentés afin de pouvoir déboguer la façon dont les données sont liées, et également comprendre le mécanisme que Magento utilise pour créer ces balises au cas où il y en aurait d'autres.

Alan Storm
la source

Réponses:

10

Comme Raphael l'a laissé entendre, il s'avère que lorsque Magento télécharge ses modèles KnockoutJS via une demande XHR (c'est-à-dire ajax), il les transmet également via des routines d'analyse personnalisées qui recherchent un certain nombre de balises et d'attributs personnalisés

Cette analyse personnalisée est effectuée par le Magento_Ui/js/lib/knockout/template/renderermodule RequireJS. Le code source de ce module configure un certain nombre de balises et d'attributs par défaut à rechercher. Il existe également d' autres modules qui peuvent ajouter des balises et des attributs supplémentaires à ce moteur de rendu. Par exemple, les éléments suivants

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

will ajoutera la <scope/>balise et l' scopeattribut ( <div scope="...">) à la liste des attributs analysables.

Il semble que l'idée de base consiste à traduire ces balises et attributs en blocs de modèles natifs Knockout "sans balises". Par exemple, le modèle Magento KnockoutJS suivant

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

Se traduit par le code natif KnockoutJS suivant

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

Les règles exactes de cette traduction ne sont toujours pas claires pour moi - le code en Magento_Ui/js/lib/knockout/template/rendererest un peu indirect, et il semble qu'ils puissent changer de tag en tag, attribut en attribut.

J'ai préparé l'extrait de code suivant qui peut télécharger un modèle Magento KnockoutJS et le traduire en code KnockoutJS natif.

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);    
})

Quant à savoir pourquoi Magento pourrait faire cela - je pense vouloir une sorte de mise en évidence de la syntaxe et de lisibilité pour le modèle de commentaire de KnockoutJS, mais n'exclut jamais plus de raisons Mallory-ish .

Alan Storm
la source
2

Les deux balises sont implémentées sous app/code/Magento/Ui/view/base/web/js/lib/knockout/template/renderer.js, je ne suis pas trop sûr de comprendre exactement comment elles sont implémentées:

_.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 chez Digital Pianism
la source