Categories
Magento 2

Magento 2’s uiRegistry Debugging

On the frontend of Magento 2 components are constructed hierarchically. Their names are derived from a concatenation of their parent names. Looking at the checkout_index_index.xml, we can see that the checkout component contains a horrendous amount of config.

To make debugging of this gargantuan hellspawned rat’s nest easier, we can use the uiRegistry object in our browser’s console.

If we would like to get a particular object and we know the full concatenated name of the item, we can simply use something akin to the following;

requirejs('uiRegistry').get("checkout.steps.shipping-step.shippingAddress");

If however, we would like to get a uiComponent using a property name, we can instead use the get method as a query. In the example above, if we only knew the script location of the uiComponent in question, we could instead perform

requirejs('uiRegistry').get("component = Magento_Checkout/js/view/shipping");

We can also pass in a callback method as the second parameter, where the item(s) returned are passed in as parameters to that function.

Get a uiComponent By XML Name

The un-concatenated index property of a uiComponent contains the name attribute on item XML node

requirejs('uiRegistry').get('index=<XML_NAME_ATTRIBUTE>');

Getting all registered uiComponents

The get method also allows us to pass in a callback function as the first parameter, instead of a query. This will pass all items sequentially through our callback, allowing us to see exactly what is registered;

requirejs('uiRegistry').get(function(item){
    console.log(item.name, item);
});

Do this on the checkout and prepare to have an exorcist level of data vomited into your poor, unsuspecting console.

Getting a uiComponent’s children

This property is an observable knockout object, so to get the actual array, execute it as a function.

componentInstance.elems();

Traversing a uiComponent’s Children

This will output the full concatenated name of all children of the uiComponent instance

_.each(uiComponentInstance.elems(), function(child) {
    console.log(child.name);
});

Using the uiRegistry to search for uiComponents

The get method of the uiRegistry allows the searching for properties. E.g. on the checkout, the sidebar item has a sortOrder of 50. The get command always returns the first element encountered, regardless of how many match.

var component = registry.get('sortOrder = 50');

Related Magento DevDoc

Using MageSpecialist’s Debug Module

MageSpecialist’s module allows the discovery of uiComponents through their Magento browser plugin and Magento Module. This allows two way debugging of uiComponents. They can be selected and shown on the page using the extension’s console.

MageSpecialist’s module adds the attribute data-mspdevtools-ui to the root node of the uiComponent. Using the hash value of this attribute, we can use MSP’s console to search for the hash, revealing the uiComponent details.

Structure of uiComponents

Imports

Imports allow data to be imported at the time the object is created from another uiComponent. E.g.

defaults: {
    imports: {
        foo: 'customer_listing.customer_listing:name'
    }
}

This will assign foo as the value of the variable in the customer_listing name property.

Listens

The listens object on a uiComponent can be set up to fire when imports are received. E.g. using the ‘Imports’ ‘foo’ example above;

listens: {
    foo: 'functionToCall'
}

Regions

Regions allow a group of uiComponents to be rendered in one area. E.g. on the checkout page, retrieving the summary component, we can get items for a region.

requirejs('uiRegistry').get('checkout.sidebar.summary.cart_items.details').getRegion('after_details')();

Will output child items subscribed to a region; the regions array is an observable hence the function call after retreival. Region is stored in the displayArea property of child items.

uiComponent.get('displayArea');

Disabling uiComponents with XML

Use the item’s config array and set item componentDisabled to true. Follow the same XML Path of the module structure to be disabled and it will be merged.

<item name="fee" xsi:type="array">
    <item name="config" xsi:type="array">
        <item name="componentDisabled" xsi:type="boolean">true</item>
    </item>
</item>

Attaching a Component

In the component’s argument data/config/component node to set the component JS

<uicomponent_name>
    <argument name="data" xsi:type="array">
        <item name="config" xsi:type="array">
            <item name="component xsi:type="string">VENDOR_MODULE/js/js-file-path</item>
        </item>
    </argument>
</uicomponent_name>

The file itself is translated to Vendor/ModuleName/view/<area>/web/js/js-file-path.js

The actual name of the component in the uiRegistry is namespaced against of the component, essentially duplicated.

This example would be uicomponent_name.uicomponent_name

Binding using scope

Note: This is done with XHTML in adminhtml.

<div data-bind="scope:uicomponent_name.uicomponent_name">
    <!-- ko template:getTemplate() --><!-- /ko>
</div>

This will use the view model’s js for every child node of the div

getTemplate() is defined in the uiElement base class which returns this.template