what does “displayArea” and “provider” of checkout_index_index.xml mean in magento2

25 octobre 2018 0 Par admin
what does “displayArea” and “provider” of checkout_index_index.xml mean in magento2

To understand what checkoutProvider and displayArea are, you must first understand the scope you are looking in: jsLayout.

jsLayout is a bunch of JavaScript configuration for the JavaScript UI elements on the checkout page. If you look at module-checkout/view/frontend/templates/onepage.phtml, you’ll notice the following x-magento-init-data:

<script type="text/x-magento-init">
    {
        "#checkout": {
            "Magento_Ui/js/core/app": <?php /* @escapeNotVerified */ echo $block->getJsLayout();?>
        }
    }
</script>

This is where it all starts. It states:

For element #checkout, initialize the Magento_Ui/js/core/app-component with the following information: …

And the information it receives is the information created in the layout XML: jsLayout. Now, this means that everything in your XML is now passed through to the Magento_Ui/js/core/app-component (leaving plugins, and layout processors and stuff out of the equation for the moment…)

Now, I’m not going to dive into detail into how module-ui/view/base/web/js/core/app.js boils everything down, because that would make this post very, very long, but the summary is this:

The Magento_Ui/js/core/app-component creates a checkout-component.
This will be a component of the type uiComponent (this is a very generic component that can be used to defer your own custom UI components from. It comes with basic knockout template rendering and stuff).
It will us the template Magento_Checkout/web/frontend/template/onepage.html.
It will create various children (with the name errors, estimation, steps, etc…)
The steps-child will also be a uiComponent.
This cycle continues… the configuration makes children with various parameters.
Now to get to your displayArea and provider-question: As you’ve seen above, everything maps to JavaScrip classes. The first time we see the use of displayArea is when we create the steps-component, which is of the type uiComponent. So uiComponent would be a logical candidate to look for the use of displayArea.

Now, a uiComponent is a JavaScript class of the type Magento_Ui/js/lib/core/collection. (You can look this up in module-ui/view/base/requirejs-config.js). This maps to module-ui/view/base/web/js/lib/core/collection.js. Here we see the following use:

 

/**
 * Synchronizes multiple elements arrays with a core '_elems' container.
 * Performs elemets grouping by theirs 'displayArea' property.
 * @private
 *
 * @returns {Collection} Chainable.
 */
_updateCollection: function () {
    var _elems = compact(this._elems),
        grouped;

    grouped = _elems.filter(function (elem) {
        return elem.displayArea && _.isString(elem.displayArea);
    });
    grouped = _.groupBy(grouped, 'displayArea');

    _.each(grouped, this.updateRegion, this);

    this.elems(_elems);

    return this;
},

 

So what this does in effect, it ‘maps’ a uiComponent to a certain group of UI components. This is important to know, because it allows us to move UI components to other locations in the layout, by just manipulating the XML layout, just like you would do this with phtml templates that are rendered server-side. Just override the displayArea, and you can render any JavaScript UI Component anywhere else (given that the target area is also rendered somewhere).

Now for your second question: provider. Just like we’ve looked up displayArea, we should start looking at the UI Component first, which is Magento_Checkout/js/view/form/element/email. And if we look at the requirejs-config.js, we finally find module-checkout/view/frontend/web/js/view/form/element/email.js.

But … no provider is used in this class. So let’s just see if we can find anything in the class it extends: Component (which is our uiComponent-class again).

But … no provider as well. Well, uiComponent simply extends Element (which is located at module-ui/view/base/web/js/lib/core/element/element.js), so let’s just look over there:

 

/**
 * Parses 'modules' object and creates
 * async wrappers for specified components.
 *
 * @returns {Element} Chainable.
 */
initModules: function () {
    _.each(this.modules, function (name, property) {
        if (name) {
            this[property] = this.requestModule(name);
        }
    }, this);

    if (!_.isFunction(this.source)) {
        this.source = registry.get(this.provider);
    }

    return this;
},

 

Bingo! It turns out that the provider is used as a source to fetch data from. If we look at the constructor of Element, you’ll see that by default, it’s set to empty:

 

provider: '',

 

So back to our configuration. If we now read our configuration, we’ll understand that the item shippingAddress is a component of Magento_Checkout/js/view/shipping, that fetches it’s data from the checkoutProvider.

So that leaves us with two questions:

Where is checkoutProvider defined?
How is it used in the shipping JavaScript?
Well, if you’ll scroll to the bottom of checkout_index_index.xml, you’ll notice that it’s nothing more than a vanilla uiComponent:

 

<item name="checkoutProvider" xsi:type="array">
    <item name="component" xsi:type="string">uiComponent</item>
</item>

 

And if you look at module-checkout/view/frontend/web/js/view/shipping.js, you’ll see that it is used like this:

 

registry.async('checkoutProvider')(function (checkoutProvider) {
    var shippingAddressData = checkoutData.getShippingAddressFromData();

    if (shippingAddressData) {
        checkoutProvider.set(
            'shippingAddress',
            $.extend({}, checkoutProvider.get('shippingAddress'), shippingAddressData)
        );
    }
    checkoutProvider.on('shippingAddress', function (shippingAddressData) {
        checkoutData.setShippingAddressFromData(shippingAddressData);
    });
});

 

To be honest: this is where my analyzing stops, because it becomes for me also hard to search and invest what’s going on, but I hope someone else can pick it up from here …

I know it has something to do with the registry.async() returning a method that gets immediately executed with a callback function as argument, but someone else needs to explain this…

6 months after my original answer I think I can provide a better answer on what displayArea is.

In my understanding, it all comes together with Knockouts’ getTemplate()-method, the getRegion()-method, and children in UI Components. A good example of this can be seen when you’re examining vendor/magento/module-checkout/view/frontend/templates/registration.phtml and vendor/magento/module-checkout/view/frontend/web/template/registration.html.

In registration.phtml, you’ll see a default Magento UI Component that has children:

 

<script type="text/x-magento-init">
    {
        "#registration": {
            "Magento_Ui/js/core/app": {
               "components": {
                    "registration": {
                        "component": "Magento_Checkout/js/view/registration",
                        "config": {
                            "registrationUrl": "<?php /* @escapeNotVerified */ echo $block->getCreateAccountUrl(); ?>",
                            "email": "<?php /* @escapeNotVerified */ echo $block->getEmailAddress(); ?>"
                        },
                        "children": {
                            "errors": {
                                "component": "Magento_Ui/js/view/messages",
                                "sortOrder": 0,
                                "displayArea": "messages",
                                "config": {
                                    "autoHideTimeOut": -1
                                 }
                            }
                        }
                    }
                }
            }
        }
    }
</script>

 

Note the use of displayArea in the children-node. Basically, it tells Knockout that this child element should be rendered in a region called ‘messages’.

Now take a look at the top of registration.html:

 

<!-- ko foreach: getRegion('messages') -->
    <!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->

 

What this line of Knockout code basically does, is: it iterates over all child elements that are present in the displayArea ‘messages’, and renders them.

Basically, the naming is a bit confusing if you ask me. Why would you use ‘displayArea’ in one place, and ‘region’ in another place. But perhaps my assumption is totally incorrect. Perhaps a Magento core developer could shine a bit more light on this?

Please follow and like us: