sbodak/magento2-checkout-custom-form

Dynamic Dropdown

webusat opened this issue · 8 comments

Hi,

How could I add a dropdown that was dynamic instead of static like the one you created?

As a test before I try the dropdown I am trying a input text box:

<item name="shippingAddress" xsi:type="array">
    <item name="children" xsi:type="array">
      <item name="custom-checkout-form" xsi:type="array">
        <item name="component" xsi:type="string">uiComponent</item>
        <item name="displayArea" xsi:type="string">custom-checkout-form</item>
           <item name="children" xsi:type="array">
               <item name="custom-checkout-form-container" xsi:type="array">
                   <item name="sortOrder" xsi:type="string">0</item>
                   <item name="component" xsi:type="string">VENDOR_MODULE/js/view/checkout/custom-checkout-form</item>
                   <item name="provider" xsi:type="string">checkoutProvider</item>
                   <item name="config" xsi:type="array">
                       <item name="shippingTemplate" xsi:type="string">VENDOR_MODULE/shipping</item>
                   </item>
                   <item name="children" xsi:type="array">
                      <item name="custom-shipping-method-fields" xsi:type="array">
                          <item name="component" xsi:type="string">uiComponent</item>
                          <item name="displayArea" xsi:type="string">custom-shipping-method-fields</item>
                          <item name="children" xsi:type="array">
                          </item>
                      </item><!-- /custom-shipping-method -->
                   </item><!-- /children -->
                </item><!-- /custom-checkout-form-container -->
            </item><!-- /children -->
        </item><!-- /custom-checkout-form -->
  </item><!-- /children -->
</item><!-- /shippingAddress -->

and

$jsLayout['components']['checkout']['children']['steps']['children']['shipping-step']['children']
      ['shippingAddress']['children']['custom-shipping-method-fields']['children']['checkout_buyer_name'] = [
          'component' => 'Magento_Ui/js/form/element/abstract',
          'config' => [
              'customScope' => 'customCheckoutForm',
              'template' => 'ui/form/field',
              'elementTmpl' => 'ui/form/element/input',
              'id' => 'checkout_buyer_name'
          ],
          'dataScope' => 'customCheckoutForm.checkout_buyer_name',
          'label' => 'Buyer Name 2',
          'provider' => 'checkoutProvider',
          'visible' => true,
          'validation' => $validation,
          'sortOrder' => 2,
          'id' => 'custom_checkout_form[checkout_buyer_name]'
      ];

I also have this to show the data:

<!-- Custom form -->
<li id="opc-custom-checkout-form"
    data-bind="fadeVisible: visible()">
    <div class="custom-checkout-form">
        <div class="step-title"
             translate="'Other information - shipping.html'"
             data-role="title" /><!-- name from checkout_index_index display area -->
        <!-- ko foreach: getRegion('custom-shipping-method-fields') -->
        <!-- ko template: getTemplate() --><!-- /ko -->
        <!--/ko-->
    </div>
</li>

With no luck. The field doesn't appear.

I even changed jsLayot to:

$jsLayout['components']['checkout']['children']['steps']['children']['shipping-step']['children']
      ['shippingAddress']['children']['custom-checkout-form']['children']['custom-checkout-form-container']['children']['custom-shipping-method-fields']['children']['checkout_buyer_name'] = [
          'component' => 'Magento_Ui/js/form/element/abstract',
          'config' => [
              'customScope' => 'customCheckoutForm',
              'template' => 'ui/form/field',
              'elementTmpl' => 'ui/form/element/input',
              'id' => 'checkout_buyer_name'
          ],
          'dataScope' => 'customCheckoutForm.checkout_buyer_name',
          'label' => 'Buyer Name 2',
          'provider' => 'checkoutProvider',
          'visible' => true,
          'validation' => $validation,
          'sortOrder' => 2,
          'id' => 'custom_checkout_form[checkout_buyer_name]'
      ];

And nothing worked.

If I use this below with everything else staying the same including the previous jsLayout at the top it works but I am trying to save the data to the DB and need those other fields.

<item name="shippingAddress" xsi:type="array">
    <item name="config" xsi:type="array">
        <item name="shippingTemplate" xsi:type="string">VENDOR_MODULE/shipping</item>
    </item>
    <item name="children" xsi:type="array">
        <item name="custom-shipping-method-fields" xsi:type="array">
            <item name="component" xsi:type="string">uiComponent</item>
            <item name="displayArea" xsi:type="string">custom-shipping-method-fields</item>
            <item name="children" xsi:type="array">
            </item>
        </item><!-- /custom-shipping-method -->
    </item><!-- /children -->
</item><!-- /shippingAddress -->

Do you know what I might be doing wrong?

Thanks,
Stan

@webusat Take a look at my answer here. You are able to add dropdown input very fast using UI component: #1 (comment)

@sbodak That won't work for my needs. I need the drop down to be dynamic and not hard coded into checkout_index_index.xml file like your example. That's why I posted the above code.

I need to be able to get the values in the LayoutProcessor from Dynamic Rows in the admin. For the Dynamic Rows I can already create the rows, get the serialized data from the database and save it as a variable and display it but I cannot for some reason convert your form into a dynamic form using the LayoutProcessor and jsLayout. It's has been a week and I haven't been able to make it work. Nothing will show on the page Any help you can provide would be greatly appreciated since so far no amount of Googling and reading Magento Docs have provided the answers I need.

Any help you can provide on taking your form and create it using jsLayout would be great!

Thanks,
Stan

@webusat Got it.
You can try to change xsi:type="array" to xsi:type="object" for dynamic resource.

<item name="options" xsi:type="object">[dynamic resource class name]</item>

@sbodak So I am just changing the section your wrote that contains the options? I am not sure what to use for [dynamic resource class name]. Or is it better to convert the whole form? I kinda wanted to convert the whole form. Whatever guidance/best practice or examples you can give is really appreciated!

Thank you so much for getting back to me!!
Stan

@webusat Try to find in the vendor examples of <item name="options" xsi:type="object"> implementations.
[dynamic resource class name] it is a reference path to you class name, for example \Bodak\CheckoutCustomForm\Model\Options, where the class implements \Magento\Framework\Data\OptionSourceInterface, \Magento\Framework\View\Element\Block\ArgumentInterface, with toOptionArray method:

    /**
     * @return array
     */
    public function toOptionArray()
    {
        $options = [
            [
                'value' => '1',
                'label' => 'Opt 1'
            ],
            [
                'value' => '2',
                'label' => 'Opt 2',
            ],
            [
                'value' => '3',
                'label' => 'Opt 3',
            ],
            [
                'value' => '4',
                'label' => 'Opt 4',
            ]
        ];

        return $options;
    }

@sbodak Thanks so much for the help. Here it what I have so far:

namespace Vendor\Module\Model\Options;

use \Magento\Framework\Data\OptionSourceInterface;
use \Magento\Framework\View\Element\Block\ArgumentInterface;

class Options implements OptionSourceInterface
{

    /**
     * @return array
     */
    public function toOptionArray()
    {
        $options = [
            [
                'value' => '1',
                'label' => 'Opt 1'
            ],
            [
                'value' => '2',
                'label' => 'Opt 2',
            ],
            [
                'value' => '3',
                'label' => 'Opt 3',
            ],
            [
                'value' => '4',
                'label' => 'Opt 4',
            ]
        ];

        return $options;
    }
}

and my xml:

<item name="checkout_building_address" xsi:type="array">
    <item name="component" xsi:type="string">Magento_Ui/js/form/element/select</item>
    <item name="config" xsi:type="array">
      <!--customScope is used to group elements within a single form (e.g. they can be validated separately)-->
      <item name="customScope" xsi:type="string">customCheckoutForm</item>
      <item name="template" xsi:type="string">ui/form/field</item>
      <item name="elementTmpl" xsi:type="string">ui/form/element/select</item>
    </item>
    
    <item name="options" xsi:type="object">
        Vendor_Module/Model/Options/Options
    </item>

    <!-- value element allows to specify default value of the form field -->
    <item name="value" xsi:type="string">Please Select Value</item>
    <item name="provider" xsi:type="string">checkoutProvider</item>
    <item name="dataScope" xsi:type="string">customCheckoutForm.checkout_building_address</item>
    <item name="label" xsi:type="string">Select Building Address</item>
    <item name="sortOrder" xsi:type="string">2</item>
</item>
<item name="checkout_comment" xsi:type="array">
    <item name="component" xsi:type="string">Magento_Ui/js/form/element/abstract</item>
    <item name="config" xsi:type="array">
        <item name="customScope" xsi:type="string">customCheckoutForm</item>
        <item name="template" xsi:type="string">ui/form/field</item>
        <item name="elementTmpl" xsi:type="string">ui/form/element/textarea</item>
        <item name="cols" xsi:type="string">15</item>
        <item name="rows" xsi:type="string">2</item>
    </item>
    <item name="provider" xsi:type="string">checkoutProvider</item>
    <item name="dataScope" xsi:type="string">customCheckoutForm.checkout_comment</item>
    <item name="label" xsi:type="string">Comment</item>
    <item name="sortOrder" xsi:type="string">5</item>
</item>
</item>

And still nothing. The log says that the class Vendor_Module/Model/Options/Options does not exist. What do I have wrong?

UPDATE
I think this was wrong:

<item name="options" xsi:type="object">
        Vendor_Module/Model/Options/Options
</item>

and should have had the slashes like this:

<item name="options" xsi:type="object">
        Vendor_Module\Model\Options\Options
</item>

I now get this:

main.CRITICAL: Instance of Magento\Framework\View\Element\Block\ArgumentInterface is expected, got Vendor\Module\Model\Options\Options instead.

UPDATE 2

This loads everything but the values into the form:

namespace Vendor\Module\Model\Options;

use Magento\Framework\View\Element\Block\ArgumentInterface;

class Options implements ArgumentInterface
{
    /**
     * @return array
     */
    public function toOptionArray()
    {
        $options = [
            [
                'value' => '1',
                'label' => 'Opt 1'
            ],
            [
                'value' => '2',
                'label' => 'Opt 2'
            ],
            [
                'value' => '3',
                'label' => 'Opt 3'
            ],
            [
                'value' => '4',
                'label' => 'Opt 4'
            ]
        ];

        return $options;
    }
}

I'll keep digging around but if you have a fix let me know.

Thanks,
Stan

@sbodak Hi, I still can't seem to find what I am doing wrong. Can you verify that this will work?

Thanks for all of your help!