KnockoutJs and Magento 2 uiComponent

Abhishek Jakhotiya
3 min readJul 18, 2020

--

Magento2 ui library seemed overwhelming when I first started working with it. Not knowing knockout.js was part of the reason. I went through knockout docs and tutorials. It only frustrated me because the way magento uses knockout wasn’t very straight forward. Take a look at javascript code in Magento_Ui module and you will quickly realize knockout is only half the story. By digging into the code I’ve realised you need to understand following things about ui system :

  • What does uiRegistry do? (stores all your UI components)
  • Objects returned by requirejs are singletons
  • uiComponent javascript module return a constructor
  • Magento’s custom knockout scope binding.
  • uiComponent module understands children node
  • how to create your own observable without directly using knockout
  • Difference between uiComponent and uiElement
  • setting up communication between two components by using data provider

Product listing Component

To look at ui components from pure frontend perspective, following json is where it ALL begins.

magento x-init json from product listing

As you can notice this JSON is 4268 lines long. It is a complete set of instructions on how to build grid. So it all begin by Magento_Ui/js/core/app` taking in all that JSON configuration and building components from it. We see two nodes in there. types and components. I’m yet not fully aware of what types node is for. Thus lets start with components node since this is the one where real work is done.

This is the birds-eye view for component node:

product_listing component node

The main parent node product_listing has two childs. First child is named product_listing and second one is product_listing_data_source. The former is responsible for all of the view layer and view logic. HTML will be rendered for this component because it has a template associated with it. We will see that shortly.

Second component, product_listing _data_source is responsible for data. It will fetch data, whenever you use pagination or use filters. It’ job is to take care of data. All of you view components will depend of this data source for there data. data_source components don’t have any html template associated with them hence they are not rendered.

To take a small detour from the JSON above, let’s peek at file name requirejs-config.js from Magento_Ui module.

Magento_Ui requirejs config

There are two things to remember.

  1. Most ui components extend either ‘uiComponent’ or ‘uiCollection’. There isn’t any difference between these two components because they point to the same file. Two separate aliases for a single file could be because of legacy reasons or some internal reason on Magento2 team. Point is, most uiComponents like listing and filters and form components extend from uiComponents.
  2. Your data source will generally extend uiElement class. It will collaborate with other “model” objects to fetch data or filter data.

`Magento_Ui/js/lib/core/collection` also known as ‘uiComponent’ is the view. It has a template. The default template will try to render all children components. For example product_listing has two children components, *listing_top* and *product_columns*.

product_listing with two children

Also if you look at config node you will notice,product_listing is a ‘uiComponent’. What that means is, for name “product_listing” utilise `Magento_Ui/js/lib/core/collection`

Default template for uiComponent is `collection.html`. All it does is render all children recursively. You will notice a pattern in this JSON.

"your_component_name":{
"name":"kinda redundunt eh",
"config":{
"component":"path/to/your/javascript",
"more-options"://can be anything you want
"template":"you will have this available in your js"
},
"children":{
//if you have your template for parent
// then you are responsible for rendering
// children the way you want
}
}

--

--