I thought I’d finished up with UI Components, but then I started investigating the checkout application and stumbled across regions.
In the aforementioned UI Components series, we learned that a “UI Component” is a nested tree of RequireJS modules and KnockoutJS templates which a programmer can use as an HTML node’s KnockoutJS view model via a custom data-binding named scope.
However, it looks like there’s another organizing method for UI Components. When you call insertChild on auiCollection/Magento_Ui/js/lib/core/class object, Magento will check the child object you’re inserting for a displayArea property. If it finds this property, Magento will update an internal regions property on the uiCollection object. You can see this on the checkout page with a little console javascript
reg = requirejs('uiRegistry');
reg.get('checkout').regions
Object {}
authentication: function...
estimation: function...
messages: function...
progressBar: function...
sidebar: function...
steps: function...
You can see the individual components inside a region via the getRegion method
reg = requirejs('uiRegistry')
reg.get('checkout').getRegion('steps')()
This returns an array of instantiated view model objects. So when you call the following via a KnockoutJS template
#File: vendor/magento/module-checkout/view/frontend/web/template/onepage.html
<!-- ko foreach: getRegion('steps') -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->
Knockout is foreaching over the same array returned by a call to requirejs('uiRegistry').get('checkout').getRegion('steps')().
The aforementioned displayArea property that organizes items into these region buckets comes from the x-magento-init JSON object. When the Magento_Ui/js/core/renderer/layout module (covered briefly in UI Component Data Sources) reads through and parses this JSON data, it ends up calling insertChild on the uiCollection objects.
The Magento_Ui/js/core/renderer/layout module is still a bit of a mystery to me, but it seems like only direct children of a uiCollection model can have a displayArea/region (as a uiCollection object is the only object with a getRegion or insertChild method).
This also seems like something that’s more of a thing in the front end UI Component/Knockout Scopes like the checkout, but the backend braintree UI Component XML seems to use displayAreas
vendor/magento/module-braintree/view/adminhtml/ui_component/braintree_report.xml
44: <item name="displayArea" xsi:type="string">dataGridActions</item
58: <item name="displayArea" xsi:type="string">dataGridActions</item
66: <item name="displayArea" xsi:type="string">dataGridFilters</item
and there’s some mentions of displayArea in the stock component definitions.
vendor/magento/module-ui/view/base/ui_component/etc/definition.xml
25: <item name="displayArea" xsi:type="string">bottom</item>
38: <item name="displayArea" xsi:type="string">dataGridFilters</item>
54: <item name="displayArea" xsi:type="string">dataGridFilters</item>
90: <item name="displayArea" xsi:type="string">bottom</item>
406: <item name="displayArea" xsi:type="string">dataGridActions</item>
419: <item name="displayArea" xsi:type="string">dataGridActions</item>
So this is definitely a universal UI Component feature.
This looks like a useful feature – but this second shadow hierarchy does create some confusing situations. For example, the onepage.html template has the following
#File: vendor/magento/module-checkout/view/frontend/web/template/onepage.html
<!-- ko foreach: getRegion('messages') -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->
However, there’s no direct child of the checkout uiComponent named messages. There is, however, a checkout.errors child with a displayArea of messages
console.log(reg.get('checkout.errors').displayArea);
messages
This is the view Magento’s fetching with getRegion('messages').