How to subscribe admin form knockout observers in Magento2

In this article, we are going learn how to create a subscriber for magento2 admin form elements.
Working on magento2 is quite fun but sometimes it feels quite annoying of the fact that, a very simple task such as adding a change event on admin form element or getting its value on form load can take hours.
Magento2 uses a very hi-tech code architecture on server-end like dependency injection, code generation, service contracts, but it is even more hi-tech on ui-end and most of the PHP developers use javascript in their daily work, but they use very basic javascript functions, very few understand the advanced javascript concepts and magento2 is full of these things.

It is very hard to see and understand things that you don’t understand very well, and magento2 javascript code architecture is one of them. Now back to our topic, how we can get admin form element value on form load, it seems very simple a simple jquery code can do this:

require(['jquery'], function($) {
    console.log($('input[name="product[name]"]').val());
})

what you will do is to add the above code in a phtml file and load the phtml from the catalog_product_edit.xml layout to the content, header, footer or anywhere on the page, but it will simply give you an undefined message in the console, since magento2 admin form is purely knockout driven all the form elements starts loading after the page is loaded so there is only one way to do that is to use knockout and get the observable value of the product name field.

So the first step is to load you knockout component in the magento2 admin form, create this file in your module:

CompanyName/ModuleName/view/adminhtml/ui_component/product_form.xml

<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
<container name="my_component_container">
    <argument name="data" xsi:type="array">
        <item name="config" xsi:type="array">
            <item name="sortOrder" xsi:type="number">1</item>
            <item name="component" xsi:type="string">CompanyName_ModuleName/js/components/my-component</item>
        </item>
    </argument>
</container>
</form>

 

This is how easily you call any component on the admin forms, the above code will load your component on the product form.

Now let’s create the component file:

define(
    [
    'underscore',
    'uiComponent',
    'ko',
    'jquery',
    'mage/translate',
    ],
    function (_, Component, ko, $, $t) {
        'use strict';

        return Component.extend(
            {
                defaults: {
                    template: 'CompanyName_ModuleName/template.html',
                    productName: '',
                    productDescription:'',
                    imports: {
                        productName: '${ $.provider }:data.product.name',
                        productDescription: '${ $.provider }:data.product.description'
                    },
                },

                /**
                 * execution starts
                 */
                initialize: function () {
                    var self = this;
                    this._super();
                    self.initSubscribers();
                },

                /**
                 * init observers
                 */
                initObservable: function () {
                    this._super().observe(
                        'productName productDescription'
                    );

                    return this;
                },

                /**
                 * initialize subscribers
                 */
                initSubscribers: function () {
                    var self = this;

                    //consoling the initial values of the product name and description after page loads
                    console.log(self.productName());
                    console.log(self.productDescription());

                    //creating a knockout subscriber to observe any changes in the product name
                    self.productName.subscribe(
                        function (productName) {
                            console.log(productName);
                        }
                    );
                    //creating a knockout subscriber to observe any changes in the product description
                    self.productDescription.subscribe(
                        function (productDescription) {
                            console.log(productDescription)
                        }
                    );           
                },
            }
        );
    }
);

As you can see in the above code I have extended the uiComponent and set some default values, you can see the imports property there I have defined productName and productDescription as ${ $.provider }:data.product.name and ${ $.provider }:data.product.description, in this string ${ $.provider } is the form data provider and data.product.name is the attribute to get, similarly you can define any form attributes here, I am not going in depth of all these stuff since these can be very time taking but I will surely write about these topics as well in the future.

You can see the initSubscribers property there I have subscribed the productName and productDescription  observers, so that if there is any change in the values I can do whatever I want and I also console log the initial values.

So to observe the magento2 admin form values you need to do the above code in your module.

Hope the above code will help you if you have any doubt please let me know in the comments below.

Thanks

. . .

Ask a Feature