Formulário de pagamento - Como agrupar vários elementos em uma classe - Magento 2

14

Como você agrupa dois elementos do formulário de checkout dentro de uma div?

Por exemplo, digamos que eu queira agrupar esses campos de país e CEP / código postal em uma div com a classe de example-class, como eu faria isso?

insira a descrição da imagem aqui

O que eu tentei

Tentei conseguir isso adicionando-os como filhos de, <item name="shippingAddress" xsi:type="array">mas isso apenas causa erros no frontend. Embora eu tenha recebido uma entrada de texto em branco sem uma etiqueta dentro.example-class houve erros no frontend.

O erro: Cannot read property 'indexedOptions' of undefined

Esta é minha tentativa rápida:

Magento_Checkout / web / template / endereço-de-entrega / form.html

<div id="shipping-new-address-form" class="fieldset address">
    <div class="testing">
        <!-- ko foreach: getRegion('example-class') -->
        <!-- ko template: getTemplate() --><!-- /ko -->
        <!--/ko-->
    </div>
    <!-- ko foreach: getRegion('additional-fieldsets') -->
    <!-- ko template: getTemplate() --><!-- /ko -->
    <!--/ko-->
</div>

checkout_index_index.xml

<item name="example-for-adding-class" xsi:type="array">
    <item name="component" xsi:type="string">uiComponent</item>
    <item name="config" xsi:type="array">
        <item name="deps" xsi:type="array">
            <item name="0" xsi:type="string">checkoutProvider</item>
        </item>
    </item>
    <item name="displayArea" xsi:type="string">example-class</item>
    <item name="children" xsi:type="array">
        <!-- The following items override configuration of corresponding address attributes -->
        <item name="region" xsi:type="array">
            <!-- Make region attribute invisible on frontend. Corresponding input element is created by region_id field -->
            <item name="visible" xsi:type="boolean">false</item>
        </item>
        <item name="region_id" xsi:type="array">
            <item name="component" xsi:type="string">Magento_Ui/js/form/element/region</item>
            <item name="config" xsi:type="array">
                <item name="template" xsi:type="string">ui/form/field</item>
                <item name="elementTmpl" xsi:type="string">ui/form/element/select</item>
                <item name="customEntry" xsi:type="string">shippingAddress.region</item>
            </item>
            <item name="validation" xsi:type="array">
                <item name="required-entry" xsi:type="boolean">true</item>
            </item>
            <!-- Value of region_id field is filtered by the value of county_id attribute -->
            <item name="filterBy" xsi:type="array">
                <item name="target" xsi:type="string"><![CDATA[${ $.provider }:${ $.parentScope }.country_id]]></item>
                <item name="field" xsi:type="string">country_id</item>
            </item>
        </item>
        <item name="postcode" xsi:type="array">
            <!-- post-code field has custom UI component -->
            <item name="component" xsi:type="string">Magento_Ui/js/form/element/post-code</item>
            <item name="sortOrder" xsi:type="string">2</item>
            <item name="validation" xsi:type="array">
                <item name="required-entry" xsi:type="string">true</item>
            </item>
        </item>
        <item name="country_id" xsi:type="array">
            <item name="sortOrder" xsi:type="string">1</item>
        </item>
    </item>
</item>

Tem que haver uma maneira mais fácil de fazer isso, ou estou faltando alguma coisa ou esta é a definição de excesso de engenharia. Adicionar uma div sobre dois elementos nunca deve ser tão difícil.

Ben Crook
fonte

Respostas:

17

Pergunta muito interessante. Deixe-me responder à última suposição sobre a implementação do Checkout. Pode ser um excesso de engenharia, já que você precisa adicionar mais do que apenas uma alteração em um arquivo.

A abordagem não requer a realização de modificações nos módulos principais do Magento 2.

Para atingir seu objetivo e agrupar os campos de endereço de entrega da verificação geral em um elemento personalizado, os seguintes elementos devem ser adicionados:

  1. Arquivo checkout_index_index.xml customizado com a nova definição de Componente da UI
  2. Novo modelo HTML com elemento personalizado
  3. Plug-in do processador de layout
  4. A declaração di.xml para o novo plug-in

O arquivo Custom_Checkout \ view \ frontend \ layout \ checkout_index_index.xml :

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="checkout" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
    <referenceBlock name="checkout.root">
        <arguments>
            <argument name="jsLayout" xsi:type="array">
                <item name="components" xsi:type="array">
                    <item name="checkout" xsi:type="array">
                        <item name="children" xsi:type="array">
                            <item name="steps" xsi:type="array">
                                <item name="children" xsi:type="array">
                                    <item name="shipping-step" xsi:type="array">
                                        <item name="children" xsi:type="array">
                                            <item name="shippingAddress" xsi:type="array">
                                                <item name="children" xsi:type="array">
                                                    <item name="shipping-address-fieldset" xsi:type="array">
                                                        <item name="children" xsi:type="array">
                                                            <item name="custom-field-group" xsi:type="array">
                                                                <item name="component" xsi:type="string">uiComponent</item>
                                                                <item name="sortOrder" xsi:type="string">0</item>
                                                                <item name="template" xsi:type="string">Custom_Checkout/checkout/field-group</item>
                                                                <item name="children" xsi:type="array">
                                                                    <item name="field-group" xsi:type="array">
                                                                        <item name="component" xsi:type="string">uiComponent</item>
                                                                        <item name="displayArea" xsi:type="string">field-group</item>
                                                                    </item>
                                                                </item>
                                                            </item>
                                                        </item>
                                                    </item>
                                                </item>
                                            </item>
                                        </item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </item>
                </item>
            </argument>
        </arguments>
    </referenceBlock>
</body>

No layout, devemos adicionar o novo componente de interface do usuário do grupo de campos personalizados . O componente possui seu próprio modelo Custom_Checkout \ view \ web \ template \ checkout \ field-group.html onde todos os campos são renderizados. Além disso, o componente custom-field-group possui um valor "0" para o nó sortOrder . Permite renderizar o componente antes de todos os campos declarados como parte do campo de endereço de entrega componente de .

Além disso, há um componente de interface do usuário do grupo de campos com sua própria displayArea configuração .

O arquivo de modelo Custom_Checkout \ view \ web \ template \ checkout \ field-group.html :

<div class="custom">
<!-- ko foreach: getRegion('field-group') -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->
</div>

O modelo permite renderizar todos os componentes adicionados à região do grupo de campos (também conhecido como displayArea ).

O arquivo de classe Custom \ Checkout \ Plugin \ AddressLayoutProcessor :

namespace Custom\Checkout\Plugin;

use Magento\Checkout\Block\Checkout\LayoutProcessor;

/**
 * Class AddressLayoutProcessor
 */
class AddressLayoutProcessor
{
    /**
     * @param LayoutProcessor $subject
     * @param array $jsLayout
     * @return array
     */
    public function afterProcess(LayoutProcessor $subject, array $jsLayout)
    {
        $fieldGroup = &$jsLayout['components']['checkout']['children']['steps']['children']['shipping-step']
            ['children']['shippingAddress']['children']['shipping-address-fieldset']
            ['children']['custom-field-group']['children']['field-group']['children'];

        $shippingAddressFields = &$jsLayout['components']['checkout']['children']['steps']['children']['shipping-step']
            ['children']['shippingAddress']['children']['shipping-address-fieldset']['children'];

        $fieldGroup['country_id'] = $shippingAddressFields['country_id'];
        $fieldGroup['postcode'] = $shippingAddressFields['postcode'];

        $shippingAddressFields['country_id']['visible'] = false;
        $shippingAddressFields['postcode']['visible'] = false;

        return $jsLayout;
    }
}

A classe é responsável por copiar as configurações dos campos country_id e postcode no componente de grupo de campos personalizados recém-criado .

Os campos, uma vez atribuídos ao grupo de campos personalizados, devem ser marcados como ocultos (visible = true) para evitar duplicação durante a renderização. O componentDisabled não deve ser usado para desativar o country_id e o código postal devido a outras dependências (por exemplo, arquivo region.js) e ao mecanismo de processamento do endereço de entrega.

O arquivo Custom \ Checkout \ etc \ frontend \ di.xml :

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Checkout\Block\Checkout\LayoutProcessor">
        <plugin name="customFieldGroupPlugin" type="Custom\Checkout\Plugin\AddressLayoutProcessor"/>
    </type>
</config>

A abordagem de plug-in usada para os campos muda porque os campos devem ser copiados com a configuração completa. No caso de o Processador de layout declarado em um módulo personalizado, o plug-in detectará alterações.

Como resultado, os campos country_id e postcode são renderizados no formulário de endereço de entrega e agrupados no elemento personalizado conforme a seguir (adicionei alguns estilos para a classe CSS personalizada se destacar no formulário):

insira a descrição da imagem aqui

Se você também quiser fazer modificações em um formulário de endereço de cobrança, o Custom \ Checkout \ Plugin \ AddressLayoutProcessor classe deve ser atualizada. Tudo o que você precisa fazer é realizar as mesmas manipulações com o endereço de cobrança para um método de pagamento específico que temos para os campos de endereço de entrega.

Feliz por ajudar!

Max Pronko
fonte
Incrível, obrigado! Eu nunca teria conseguido isso, interessante como isso exige trabalho de back-end. Eu estava lidando com isso do ponto de vista puramente FE. Se ninguém chegar a uma solução mais simples em alguns dias (como eu acho que outras pessoas estão olhando para isso), vou marcar como aceito. Obrigado novamente.
Ben Crook
Excelente resposta :)
Keyur Shah
Impressionante, muito obrigado. Funciona para mim.
Pratik Mehta 22/01
Se pretender a mesma alteração, aplica-se ao novo endereço de cobrança?
Pratik Mehta 23/01
1
Se você também quiser fazer modificações em um formulário de endereço de cobrança, a classe Custom \ Checkout \ Plugin \ AddressLayoutProcessor deve ser atualizada. Tudo o que você precisa fazer é realizar as mesmas manipulações com o endereço de cobrança para o método de pagamento específico que temos nos campos de endereço de entrega.
Max Pronko 23/01
2

Esta não é uma maneira recomendada, é simples, mas não é elegante:

app / code / Vendor / Module / view / frontend / layout / checkout_index_index.xml

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="checkout" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="content">
          <block class="Vendor\Salesman\Block\Checkout\Index" name="custom_checkout" before="-" template="Vendor_Module::checkout/index.phtml"/>
        </referenceContainer>
    </body>
</page>

app / code / Lime / Salesman / view / frontend / templates / checkout / index.phtml

<script>
  require([
      'jquery',
      'mage/mage'
  ], function($){
      $(document).ready(function () {
         //detect if the shipping form container loaded
         var existCondition = setInterval(function() {
            if ($('#shipping').length) {
              moveElement();
            }
         }, 100);

         function moveElement(){
             //get The field postcode and country
             var postcodeField = $("div[name='shippingAddress.postcode']");
             var countryField = $("div[name='shippingAddress.country_id']");
             // insert the wrapeer
             $( '<div class="wrapper"></div>' ).insertBefore( postcodeField);
             // move the fields to wrapper
             $(".wrapper").append(postcodeField);
             $(".wrapper").append(countryField);
         }
      });
    }
  });
</script>
Shell Suite
fonte
Votei positivamente porque tenho certeza de que funcionaria, mas concordo que não é muito limpo, não usaria isso a menos que não houvesse um método mais limpo. Obrigado.
Ben Crook