Magento 2: O que é um Tag `<each />`?

13

Tão perto quanto eu posso dizer, quando você vê uma Grade no back-end do Magento, o seguinte modelo "carregado sobre XHR" KnockoutJS é o que começa a renderizar coisas

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>

No entanto - estou um pouco sem saber o que são a <each/>tag e a <render/>tag. Eles não são (ou não parecem ser?) Uma parte do estoque KnockoutJS.

Sei que é possível adicionar tags personalizadas ao KnockoutJS por meio de componentes , mas não vejo lugares óbvios em que um componente chamado eachou renderseja adicionado ao KnockoutJS.

Portanto, não tenho certeza se esses componentes estão registrados em algum lugar que não conheço, ou alguma outra personalização que o Magento fez no KnockoutJS que habilita tags personalizadas ou algo completamente diferente.

Nota: Eu não estou completamente no escuro aqui - eu entendo que <each/>provavelmente está repetindo todos os componentes da interface do usuário filho renderizados no JSON e renderizando seu modelo (se esse modelo existir).

O que não estou claro é como essas tags são implementadas. Quero ver onde eles são implementados para que eu possa depurar como os dados são vinculados e também entender o mecanismo que o Magento está usando para criar essas tags, caso existam outras.

Alan Storm
fonte

Respostas:

10

Como Raphael sugeriu, verifica-se que, quando o Magento baixa seus modelos KnockoutJS por meio de uma solicitação XHR (ajax), ele também os passa por algumas rotinas de análise personalizadas que procuram várias tags e atributos personalizados

Essa análise customizada é feita pelo Magento_Ui/js/lib/knockout/template/renderermódulo RequireJS. O código-fonte deste módulo configura um número de tags e atributos padrão para pesquisar. Também existem outros módulos que podem adicionar tags e atributos adicionais a esse renderizador. Por exemplo, o seguinte

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

irá adicionar a <scope/>tag e scopeattribute ( <div scope="...">) à lista de atributos analisáveis.

É parece que a idéia básica é traduzir estas tags e atributos em Knockout "Tagless" blocos do modelo nativas. Por exemplo, o seguinte modelo Magento KnockoutJS

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

Traduz para o seguinte código KnockoutJS nativo

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

As regras exatas dessa tradução ainda não estão claras para mim - o código Magento_Ui/js/lib/knockout/template/rendereré um pouco indireto e parece que elas podem mudar de marca para marca, atributo para atributo.

Criei o seguinte snippet de código que pode baixar um modelo Magento KnockoutJS e traduzi-lo para o código nativo 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);    
})

Quanto ao motivo pelo qual o Magento pode fazer isso - meu palpite está querendo algum tipo de destaque e legibilidade da sintaxe para o modelo de comentários do KnockoutJS, mas nunca descarta mais razões de Mallory .

Alan Storm
fonte
2

Ambas as tags são implementadas app/code/Magento/Ui/view/base/web/js/lib/knockout/template/renderer.js, porém, não tenho muita certeza de entender exatamente como elas são implementadas:

_.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 na Digital Pianism
fonte