{"id":20774,"date":"2019-03-28T14:59:43","date_gmt":"2019-03-28T12:59:43","guid":{"rendered":"https:\/\/belvg.com\/blog\/?p=20774"},"modified":"2023-10-13T16:10:34","modified_gmt":"2023-10-13T14:10:34","slug":"what-is-knockout-js-framework","status":"publish","type":"post","link":"https:\/\/belvg.com\/blog\/what-is-knockout-js-framework.html","title":{"rendered":"What is Knockout JS Framework in Magento 2?"},"content":{"rendered":"\n<p>Knockout.js &mdash; is a library that allows you to create dynamic interfaces and use different bindings for DOM elements. It implements the Model-View-ViewModel pattern and is used in Magento 2 dynamic modules such as Checkout, Customer, etc. In this article I will refer to module files that use knockout.js, and also describe how to use the framework to perform various functions in Magento 2.<\/p>\n<p><!--more--><\/p>\n<p><strong>Table of contents:<\/strong><\/p>\n<p><a href=\"#step_1\">How do you use knockout.js bindings<br>\n<\/a><a href=\"#step_2\">How do you bind a ko view model to a section of the DOM with the scope binding<br>\n<\/a><a href=\"#step_3\">How do you render a ko template of a UiComponent<br>\n<\/a><a href=\"#step_4\">Demonstrate an understanding of the different types of knockout observables<br>\n<\/a><a href=\"#step_5\">What common ko bindings are used<br>\n<\/a><a href=\"#step_6\">Demonstrate an understanding of ko virtual elements<\/a><\/p>\n<p>Before I will explore each question in greater detail, it is necessary to explain the Model-View-ViewModel.&nbsp;MVVC&nbsp;consists of 3 components:<\/p>\n<ul>\n<li>Model contains data<\/li>\n<li>View reflects the data on the screen<\/li>\n<li>ViewModel is an intermediary between Model and View, allows to obtain data for View and influence Model<\/li>\n<\/ul>\n<p>With that knowledge in mind, we can proceed to the main part of the article.<\/p>\n<h2 id=\"step_1\">How do you use knockout.js bindings<\/h2>\n<p>Binding is the ability to bind various components to HTML. In knockout.js, the html attribute data-bind is used for this. Here is how the binding is implemented, using the user greeting component on the frontend of Magento 2 as the example:<\/p>\n<p>https:\/\/github.com\/magento\/magento2\/blob\/2.2\/app\/code\/Magento\/Customer\/view\/frontend\/templates\/account\/customer.phtml<\/p>\n<pre class=\"lang:default decode:true\">&lt;span data-bind=\"text: customer().fullname\"&gt;&lt;\/span&gt;<\/pre>\n<p>If we assume that the value of <strong>fullname<\/strong> is observable, then as soon as the value of <strong>fullname<\/strong> changes, this value changes correspondingly on the website.<\/p>\n<p>There are many different bindings, and all of them are described in the knockout.js documentation&nbsp;(https:\/\/knockoutjs.com\/documentation\/introduction.html). Here are some of them: <strong>visible, text, html, if, foreach, click<\/strong>.<\/p>\n<p>Also, Magento 2 has its own custom bindings, and all of them can be specified in the <strong>data-bind<\/strong> attribute, while some of them can be specified as an attribute, a virtual element <strong>knockout.js<\/strong> or as a custom element. Here are some of them:<\/p>\n<ol>\n<li>\n<pre class=\"lang:default decode:true \">&lt;!-- ko template: getTemplate() --&gt;&lt;!-- \/ko --&gt;<\/pre>\n<p>It is responsible for the output of the template specified in the component, here is the function responsible for this output:<br>\nhttps:\/\/github.com\/magento\/magento2\/blob\/2.2\/app\/code\/Magento\/Ui\/view\/base\/web\/js\/lib\/core\/element\/element.js#L266<\/p>\n<pre class=\"lang:default decode:true\">getTemplate: function () {\r\n            return this.template;\r\n        }<\/pre>\n<\/li>\n<li>\n<pre class=\"lang:default decode:true\"><i><span style=\"font-weight: 400\">&lt;!-- ko i18n: &lsquo;Text&rsquo; --&gt;&lt;!-- \/ko --&gt; <\/span><\/i><\/pre>\n<p>This is a virtual element used for translation in Magento 2. You might want to use<em> &lt;! &ndash; ko text: -&gt;<\/em>, yet bear in mind that the code I suggest was created with the aim that everything would integrate with the translations in Magento 2. You can also use <strong>data-bind<\/strong> as an attribute:<\/p>\n<pre class=\"lang:default decode:true \">&lt;span translate=\"Text\" \/&gt;\r\n&lt;span data-bind=\"i18n: 'Text'\"&gt;&lt;\/span&gt;<\/pre>\n<\/li>\n<li>\n<pre class=\"lang:default decode:true\"><span style=\"font-weight: 400\">&lt;<\/span><b>span<\/b> <span style=\"font-weight: 400\">data-bind<\/span><span style=\"font-weight: 400\">=<\/span><span style=\"font-weight: 400\">\"afterRender: setModalElement\"<\/span><span style=\"font-weight: 400\">&gt;&lt;\/<\/span><b>span<\/b><span style=\"font-weight: 400\">&gt;<\/span><\/pre>\n<p>This one is used to add a function after the item is rendered.<\/p><\/li>\n<li>\n<pre class=\"lang:default decode:true \">&lt;div data-bind=\"fadeVisble: isVisble\"&gt;&lt;\/div&gt;<\/pre>\n<p>This binding is&nbsp;used to fade in or fade out of the element depending on the function result.<\/p><\/li>\n<li>\n<pre class=\"lang:default decode:true \">&lt;div data-bind=\"mageInit: &lsquo;mywidget&rsquo;:{&lsquo;configuration-value&rsquo;:true}\"&gt;&lt;\/div&gt;<\/pre>\n<p>This binding is used to initiate jqueryUi widget.<\/p><\/li>\n<\/ol>\n<p>Here is the list of knockout bindings:<\/p>\n<p>1.Layout:<\/p>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\"><strong>visible<\/strong> &ndash; show \/ hide an element depending on the condition<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\"><strong>text<\/strong> &ndash; displays text, html tags will be displayed as text<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\"><strong>html<\/strong> &ndash; displays html, html tags will be rendered<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\"><strong>css<\/strong> &ndash; add css class depending on the condition<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\"><strong>style<\/strong> &ndash; add css style depending on the condition<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\"><strong>attr<\/strong> &ndash; set attribute values<\/span><\/li>\n<\/ul>\n<p>2.&nbsp;Flow:<\/p>\n<ul>\n<li><span style=\"font-weight: 400\"><strong>foreach<\/strong> &ndash; duplicates the element content for each item in the specified array<\/span><\/li>\n<li><span style=\"font-weight: 400\"><strong>if<\/strong> &ndash; adds the contents of the condition block to the DOM if it is true<\/span><\/li>\n<li><span style=\"font-weight: 400\"><strong>ifnot<\/strong> &ndash; adds the contents of the condition block to the DOM if it is false<\/span><\/li>\n<li><span style=\"font-weight: 400\"><strong>with<\/strong> &ndash; creates a new bundling property context in which you can refer directly to the sub-properties of this property.<\/span><\/li>\n<li><span style=\"font-weight: 400\"><strong>component<\/strong> &ndash; embeds an external component in the DOM<\/span><\/li>\n<\/ul>\n<p>3.&nbsp;Fields:<\/p>\n<ul>\n<li><span style=\"font-weight: 400\"><strong>click<\/strong> &ndash; function is called when clicked on<\/span><\/li>\n<li><span style=\"font-weight: 400\"><strong>event<\/strong> &ndash; function is called when an event occurs<\/span><\/li>\n<li><span style=\"font-weight: 400\"><strong>submit<\/strong> &ndash; function is called upon submit<\/span><\/li>\n<li><span style=\"font-weight: 400\"><strong>enable<\/strong> &ndash; turns on the element when the condition is true<\/span><\/li>\n<li><span style=\"font-weight: 400\"><strong>disable<\/strong> &ndash; disables the element when the condition is true<\/span><\/li>\n<li><span style=\"font-weight: 400\"><strong>value<\/strong> &ndash; changes the value of the form field<\/span><\/li>\n<li><span style=\"font-weight: 400\"><strong>textInput<\/strong> &ndash; similar to value, works only with text fields, provides for all types of user input, including autocomplete, drag-and-drop, and clipboard events<\/span><\/li>\n<li><span style=\"font-weight: 400\"><strong>hasFocus<\/strong> &ndash; changes the value of the property when is received (to true) and the focus is lost (to false)<\/span><\/li>\n<li><span style=\"font-weight: 400\"><strong>checked<\/strong> &ndash; changes property value when selecting checkbox and radio elements<\/span><\/li>\n<li><span style=\"font-weight: 400\"><strong>options<\/strong> &ndash; provides options for dropdown<\/span><\/li>\n<li><span style=\"font-weight: 400\"><strong>selectedOptions<\/strong> &ndash; provides selected options from the dropdown<\/span><\/li>\n<li><span style=\"font-weight: 400\"><strong>uniqueName<\/strong> &ndash; sets a unique name for form fields with an empty name<\/span><\/li>\n<\/ul>\n<p>4.&nbsp;Template rendering:<\/p>\n<ul>\n<li><strong>template<\/strong> &ndash; renders another template<\/li>\n<\/ul>\n<h2 id=\"step_2\">How do you bind a ko view model to a section of the DOM with the scope binding<\/h2>\n<p>Connects the Ui element with the component that is declared in xml in jsLayout or in <em>&lt;script type=&rdquo;text\/x-<\/em>magento<em>-init&rdquo;&gt;<\/em>, and the already registered one in <strong>uiRegistry<\/strong>.<\/p>\n<p>I will cite the checkout as an example.<\/p>\n<p>xml:<\/p>\n<pre class=\"lang:default decode:true \">   &lt;referenceContainer name=\"content\"&gt;\r\n            &lt;block class=\"Magento\\Checkout\\Block\\Onepage\" name=\"checkout.root\" template=\"Magento_Checkout::onepage.phtml\" cacheable=\"false\"&gt;\r\n                &lt;arguments&gt;\r\n                    &lt;argument name=\"jsLayout\" xsi:type=\"array\"&gt;\r\n                        &lt;item name=\"components\" xsi:type=\"array\"&gt;\r\n                            &lt;item name=\"checkout\" xsi:type=\"array\"&gt;\r\n                                &lt;item name=\"component\" xsi:type=\"string\"&gt;uiComponent&lt;\/item&gt;\r\n                                &lt;item name=\"config\" xsi:type=\"array\"&gt;\r\n                                    &lt;item name=\"template\" xsi:type=\"string\"&gt;Magento_Checkout\/onepage&lt;\/item&gt;\r\n                                &lt;\/item&gt;\r\n                        &lt;\/item&gt;\r\n                    &lt;\/argument&gt;\r\n              &lt;\/arguments&gt;\r\n            &lt;\/block&gt;\r\n        &lt;\/referenceContainer&gt;<\/pre>\n<p>In the line&nbsp;<em>&lt;item name=&rdquo;checkout&rdquo; <\/em>xsi<em>:type=&rdquo;array&rdquo;&gt;<\/em> in the attribute name we declare the component name, <strong>checkout<\/strong> in our case, and call it in phtml:<\/p>\n<pre class=\"lang:default decode:true \">&lt;div id=\"checkout\" data-bind=\"scope:'checkout'\" class=\"checkout-container\"&gt;\r\n&lt;!-- ko template: getTemplate() --&gt;&lt;!-- \/ko --&gt;\r\n&lt;\/div&gt;<\/pre>\n<p>In this example we immediately created <strong>checkout<\/strong> in xml, and then it was binded to <strong>UiRegistry<\/strong> with the help of our configurations parcing specified in xml and getting them with the help of json with &#1089; &#1087;&#1086;&#1084;&#1086;&#1097;&#1100;&#1102; &#1087;&#1072;&#1088;&#1089;&#1080;&#1085;&#1075;&#1072; &#1085;&#1072;&#1096;&#1080;&#1093; &#1085;&#1072;&#1089;&#1090;&#1088;&#1086;&#1077;&#1082; &#1091;&#1082;&#1072;&#1079;&#1072;&#1085;&#1085;&#1099;&#1093; xml &#1080; &#1087;&#1086;&#1083;&#1091;&#1095;&#1077;&#1085;&#1080;&#1077;&#1084; &#1080;&#1093; &#1089; &#1087;&#1086;&#1084;&#1086;&#1097;&#1100;&#1102; json with <strong>$block-&gt;getJsLayout()<\/strong> php function.<\/p>\n<pre class=\"lang:default decode:true \"> &lt;script type=\"text\/x-magento-init\"&gt;\r\n        {\r\n            \"#checkout\": {\r\n                \"Magento_Ui\/js\/core\/app\": &lt;?= \/* @escapeNotVerified *\/ $block-&gt;getJsLayout() ?&gt;\r\n            }\r\n        }\r\n    &lt;\/script&gt;<\/pre>\n<p>Also, if we bind a component to a DOM element through data-mage-init, the scope is bound to the element to which we have bound the component or widget.<\/p>\n<p>Example:<\/p>\n<pre class=\"lang:default decode:true \">&lt;div id=\"checkout-loader\" data-role=\"checkout-loader\" class=\"loading-mask\" data-mage-init='{\"checkoutLoader\": {}}'&gt;<\/pre>\n<p>The #<strong>checkout-loader<\/strong> element becomes the scope of the <strong>checkoutLoader<\/strong> component.<\/p>\n<h2 id=\"step_3\">How do you render a ko template of a UiComponent<\/h2>\n<p>Knockout templates can be specified in different ways, and I will try to cover possible ways to specify templates for UiComponent.<\/p>\n<p>Method #1. Specify the component in the viewmodel file itself, for example, as is done in the pop-up authorization form:<\/p>\n<p>https:\/\/github.com\/m1kash\/magento2\/blob\/2.2-develop\/app\/code\/Magento\/Customer\/view\/frontend\/web\/js\/view\/authentication-popup.js#L28<\/p>\n<p>Code:<\/p>\n<pre class=\"lang:default decode:true \">define([...], function (...) {\r\n    'use strict';\r\n\r\n    return Component.extend({\r\n        defaults: {\r\n            template: 'Magento_Customer\/authentication-popup'\r\n        },\r\n    });\r\n});\r\n<\/pre>\n<p>As you can see, the standard template <strong>Magento_Customer \/ authentication-popup<\/strong> will be used, and when we create our custom component ui, we can specify our template via mixin, layout, text \/ x-magento-init, data-mage-init.<\/p>\n<p>Method #2. Specify our template in text \/ x-magento-init:<\/p>\n<pre class=\"lang:default decode:true \">&lt;script type=\"text\/x-magento-init\"&gt;\r\n    {\r\n        \"*\": {\r\n            \"Magento_Ui\/js\/core\/app\": {\r\n                \"components\": {\r\n                        \"customComponent\": {\r\n                            \"template\": \"Magento_Theme\/template\",\r\n                            \"component\": \"Magento_Theme\/js\/view\/custom-component\"\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n    }\r\n&lt;\/script&gt;<\/pre>\n<p>Method #3. Specify in <strong>jsLayout<\/strong>, the way it was done in checkout:<\/p>\n<pre class=\"lang:default decode:true \">&lt;item name=\"summary\" xsi:type=\"array\"&gt;\r\n  &lt;item name=\"component\" xsi:type=\"string\"&gt;Magento_Checkout\/js\/view\/summary&lt;\/item&gt;\r\n  &lt;item name=\"displayArea\" xsi:type=\"string\"&gt;summary&lt;\/item&gt;\r\n  &lt;item name=\"config\" xsi:type=\"array\"&gt;\r\n  &lt;item name=\"template\" xsi:type=\"string\"&gt;Magento_Checkout\/summary&lt;\/item&gt;&lt;\/item&gt;\r\n  &lt;item name=\"children\" xsi:type=\"array\"&gt;&lt;\/item&gt;\r\n&lt;\/item&gt;<\/pre>\n<p>For the Magento_Checkout \/ js \/ view \/ summary component, apply the template that we specified in <strong>xml: Magento_Checkout \/ summary<\/strong>.<\/p>\n<p>Method #4. Specify the template directly in the template where our component is called the following way:<\/p>\n<pre class=\"lang:default decode:true \">&lt;!-- ko template: \"BelVG_CustomModule\/custom-template\" --&gt;&lt;!-- \/ko &rarr;<\/pre>\n<p>For the first 3 ways, we need to specify a call to our template, as it is done in checkout:<br>\nhttps:\/\/github.com\/magento\/magento2\/blob\/2.2\/app\/code\/Magento\/Checkout\/view\/frontend\/templates\/onepage.phtml#L17.<\/p>\n<pre class=\"lang:default decode:true \">&lt;div id=\"checkout\" data-bind=\"scope:'checkout'\" class=\"checkout-container\"&gt;\r\n    &lt;!-- ko template: getTemplate() --&gt;&lt;!-- \/ko --&gt;\r\n    &lt;script type=\"text\/x-magento-init\"&gt;\r\n        {\r\n            \"#checkout\": {\r\n                \"Magento_Ui\/js\/core\/app\": &lt;?= \/* @escapeNotVerified *\/ $block-&gt;getJsLayout() ?&gt;\r\n            }\r\n        }\r\n    &lt;\/script&gt;\r\n&lt;\/div&gt;<\/pre>\n<p>As you can see from the code, we declared the scope for the #<strong>checkout<\/strong> element and called the function <strong>getTemplate ()<\/strong> via the virtual element. To learn how the function performs follow the link (https:\/\/github.com\/magento\/magento2\/blob\/2.2\/app \/code\/Magento\/Ui\/view\/base\/web\/js\/lib\/core\/element\/element.js#L266)<br>\nbut in simple words it receives a link to the static address of our template and after all this it renders our template.<br>\nHere is the example of the github component&rsquo;s checkout template <span style=\"font-weight: 400\">(<\/span><span style=\"font-weight: 400\">https:\/\/github.com\/magento\/magento2\/blob\/2.2\/app\/code\/Magento\/Checkout\/view\/frontend\/web\/template\/onepage.html<\/span>):<\/p>\n<pre class=\"lang:default decode:true\">&lt;!--\r\n\/**\r\n * Copyright &copy; Magento, Inc. All rights reserved.\r\n * See COPYING.txt for license details.\r\n *\/\r\n--&gt;\r\n&lt;!-- ko foreach: getRegion('authentication') --&gt;\r\n&lt;!-- ko template: getTemplate() --&gt;&lt;!-- \/ko --&gt;\r\n&lt;!--\/ko--&gt;\r\n\r\n&lt;!-- ko foreach: getRegion('progressBar') --&gt;\r\n&lt;!-- ko template: getTemplate() --&gt;&lt;!-- \/ko --&gt;\r\n&lt;!--\/ko--&gt;\r\n\r\n&lt;!-- ko foreach: getRegion('estimation') --&gt;\r\n    &lt;!-- ko template: getTemplate() --&gt;&lt;!-- \/ko --&gt;\r\n&lt;!--\/ko--&gt;\r\n\r\n&lt;!-- ko foreach: getRegion('messages') --&gt;\r\n    &lt;!-- ko template: getTemplate() --&gt;&lt;!-- \/ko --&gt;\r\n&lt;!--\/ko--&gt;\r\n&lt;div class=\"opc-wrapper\"&gt;\r\n    &lt;ol class=\"opc\" id=\"checkoutSteps\"&gt;\r\n    &lt;!-- ko foreach: getRegion('steps') --&gt;\r\n        &lt;!-- ko template: getTemplate() --&gt;&lt;!-- \/ko --&gt;\r\n    &lt;!--\/ko--&gt;\r\n    &lt;\/ol&gt;\r\n&lt;\/div&gt;\r\n\r\n&lt;!-- ko foreach: getRegion('sidebar') --&gt;\r\n    &lt;!-- ko template: getTemplate() --&gt;&lt;!-- \/ko --&gt;\r\n&lt;!--\/ko--&gt;\r\n<\/pre>\n<p>It is clear from the heatworm that we use foreach, alternately displaying data from an array or $ date object, for example, in the last foreach, <strong>getRegion ()<\/strong> is used to get the sidebar and so on. The function code is in github<span style=\"font-weight: 400\">(<\/span><span style=\"font-weight: 400\">https:\/\/github.com\/m1kash\/magento2\/blob\/2.2-develop\/app\/code\/Magento\/Ui\/view\/base\/web\/js\/lib\/core\/collection.js#L205<\/span><span style=\"font-weight: 400\">).<\/span><\/p>\n<div class=\"content_sales_info\" style=\"background-image: url(https:\/\/belvg.com\/blog\/wp-content\/uploads\/2019\/03\/Sales_background.png\"><img width=\"65\" height=\"65\" src=\"https:\/\/belvg.com\/blog\/wp-content\/uploads\/2019\/03\/Igor-Dragun1.png\" alt=\"Igor Dragun\" title=\"What is Knockout JS Framework in Magento 2?\"><div class=\"content_part\"><h3 class=\"title\">Partner With Us <\/h3><span class=\"sales_content_text\">Let's discuss how to grow your business. Get a Free Quote.<\/span><\/div> <a class=\"call-to-action\" href=\"https:\/\/belvg.com\/contact?utm_source=blog&amp;utm_campaign=sales_block&amp;utm_content=middle\" target=\"_blank\" rel=\"noopener\">Talk to Igor<\/a><\/div>\n<h2 id=\"step_4\">Demonstrate an understanding of the different types of knockout observables<\/h2>\n<p>Observables are the observable objects and arrays that are updated asynchronously as the value changes. In knockout.js, this is implemented by the following functions:<\/p>\n<p>1. <strong>ko.observable()<\/strong> &ndash; the function is used for observable objects to change values asynchronously, for example, when receiving data from json.<br>\n2. <strong>ko.observableArray([])<\/strong> &ndash; the function is used for the observed arrays, which can also be updated asynchronously. You can also change the values and use methods for arrays such as: .map, .filter, .each, etc.<\/p>\n<p>If we want to assign a value to the observed object or array, then we pass our value to the function argument:<\/p>\n<pre class=\"lang:default decode:true \">var Name = ko.observable(null);\r\nName('New value!');<\/pre>\n<p><a href=\"https:\/\/belvg.com\/blog\/wp-content\/uploads\/2019\/03\/understanding-knockout-framework.png\"><img decoding=\"async\" loading=\"lazy\" class=\"lazy aligncenter size-full wp-image-20867\" src=\"https:\/\/belvg.com\/wp-content\/uploads\/2019\/06\/pixel.png\" data-src=\"https:\/\/belvg.com\/blog\/wp-content\/uploads\/2019\/03\/understanding-knockout-framework.png\" alt=\"understanding knockout framework\" width=\"946\" height=\"181\" title=\"What is Knockout JS Framework in Magento 2?\"><\/a><\/p>\n<p>If we want to get a value from an observable object or array, then we call our function with no arguments:<\/p>\n<pre class=\"lang:default decode:true \">Name();<\/pre>\n<p><a href=\"https:\/\/belvg.com\/blog\/wp-content\/uploads\/2019\/03\/Understanding-knockout-framework-name.png\"><img decoding=\"async\" loading=\"lazy\" class=\"lazy aligncenter size-full wp-image-20869\" src=\"https:\/\/belvg.com\/wp-content\/uploads\/2019\/06\/pixel.png\" data-src=\"https:\/\/belvg.com\/blog\/wp-content\/uploads\/2019\/03\/Understanding-knockout-framework-name.png\" alt=\"nderstanding knockout framework name\" width=\"563\" height=\"86\" title=\"What is Knockout JS Framework in Magento 2?\"><\/a><\/p>\n<p>1. To get the value before assignment, you need to write the following structure:<\/p>\n<pre class=\"lang:default decode:true \">Name.subscribe(function(oldValue) {\r\n    alert(\"Old value: \" + oldValue);\r\n}, null, \"beforeChange\");<\/pre>\n<p>2. To get the value after assignment, you need to write the following structure:<\/p>\n<pre class=\"lang:default decode:true \">Name.subscribe(function(newValue) {\r\n    alert(\"New value: \" + newValue);\r\n});\r\n<\/pre>\n<p>Then there are also calculable functions:<\/p>\n<p>1. <strong>ko.computed(callback)<\/strong> &mdash;used to update the value when changing which observable object is used in this function.<br>\n2. <strong>ko.pureComputed(callback)<\/strong> &mdash; used to return observable objects but without update. Due to this, the performance is improved and less memory is needed than with the <strong>ko.computed<\/strong> function.<\/p>\n<p>Example of the <strong>Observables<\/strong> function.<\/p>\n<p>html:<\/p>\n<p>The name is<\/p>\n<pre class=\"lang:default decode:true \">&lt;span data-bind=\"text: name\"&gt;&lt;\/span&gt;\r\n&lt;button data-bind=\"click: change\"&gt;Change&lt;\/button&gt;\r\n<\/pre>\n<p>script:<\/p>\n<pre class=\"lang:default decode:true \">var myViewModel = {\r\n    name: ko.observable('Bob'),\r\n    change: function() {\r\n    \tthis.name('Alice');\r\n    }\r\n};\r\nko.applyBindings(myViewModel);\r\n<\/pre>\n<p>Output before pressing the <strong>Change<\/strong> button:<br>\n&ldquo;The name is Bob.&rdquo;<\/p>\n<p>Output after pressing the <strong>Change<\/strong> button:<br>\n&ldquo;The name is Alice.&rdquo;<\/p>\n<h2 id=\"step_5\">What common ko bindings are used<\/h2>\n<p>It was already mentioned that you can find most of the bindings in the knockout.js documentation <span style=\"font-weight: 400\">(<\/span><span style=\"font-weight: 400\">https:\/\/knockoutjs.com\/documentation\/introduction.html)<\/span>. Let&rsquo;s consider the main ones used in Magento:<\/p>\n<ol>\n<li>\n<pre class=\"lang:default decode:true \">&lt;div data-bind=\"visible: Observer()\"&gt;<\/pre>\n<p>It is clear from the name that this one is responsible for the visibility of the element and takes the value of boolean.<\/p><\/li>\n<li>\n<pre class=\"lang:default decode:true \">&lt;div data-bind=\"text: ObserverText()\"&gt;<\/pre>\n<p>This binding is used to display text.<\/p><\/li>\n<li>\n<pre class=\"lang:default decode:true \">&lt;p data-bind=\"html: ObserverElements()\"&gt;<\/pre>\n<p>This binding is used for html output.<\/p><\/li>\n<li>\n<pre class=\"lang:default decode:true \">&lt;form data-bind=\"attr: {'data-hasrequired': $t('* Required Fields')}\"&gt;<\/pre>\n<p><strong>attr<\/strong> binding is used for attributes output.<\/p><\/li>\n<li>\n<pre class=\"lang:default decode:true \">&lt;button data-bind=\"click: function\"&gt;<\/pre>\n<p>The binding is used to bind the function to the event when the element is clicked; if the function is callback, then we indicate only the name without calling.<\/p>\n<p>These were the bindings most commonly used in Magento, and as I have already mentioned, the rest can be found on the official website knockout.js in the documentation.<\/p><\/li>\n<\/ol>\n<h2 id=\"step_6\">Demonstrate an understanding of ko virtual elements<\/h2>\n<p>Virtual elements are a child element binding without the need to insert html to bind an element. Virtual elements are used to render the html document. Here is the example of how it is done in the template of payment methods&nbsp;<span style=\"font-weight: 400\">(<\/span><span style=\"font-weight: 400\">https:\/\/github.com\/m1kash\/magento2\/blob\/2.2-develop\/app\/code\/Magento\/Checkout\/view\/frontend\/web\/template\/payment.html<\/span>):<\/p>\n<pre class=\"lang:default decode:true \">  &lt;!-- ko foreach: getRegion('payment-methods-list') --&gt;\r\n                        &lt;!-- ko template: getTemplate() --&gt;&lt;!-- \/ko --&gt;\r\n                    &lt;!-- \/ko --&gt;<\/pre>\n<p>These are the most common virtual elements used in Magento 2:<\/p>\n<ol>\n<li>\n<pre class=\"lang:default decode:true \">&lt;!-- ko foreach: $data --&gt;&lt;!-- \/ko --&gt;<\/pre>\n<p>used to iterate over arrays to display date from an array.<\/p><\/li>\n<li>\n<pre class=\"lang:default decode:true \"> &lt;!-- ko template: getTemplate() --&gt;&lt;!-- \/ko --&gt;<\/pre>\n<p>used to output data from an array according to the template that we will specify in the template.<\/p><\/li>\n<li>\n<pre class=\"lang:default decode:true \">&lt;!-- ko if: function()--&gt;&lt;!-- \/ko --&gt;<\/pre>\n<p>used to check the condition of data display from the condition; there is also<\/p>\n<pre class=\"lang:default decode:true \">&lt;!-- ko ifnot: conditionFunc() --&gt;&lt;!-- \/ko --&gt;<\/pre>\n<p>this one is used for opposite conditions.<\/p><\/li>\n<li>\n<pre class=\"lang:default decode:true \">&lt;!-- ko i18n: 'of' --&gt;&lt;!-- \/ko --&gt;<\/pre>\n<p>used for translation in Magento 2.<\/p><\/li>\n<li>\n<pre class=\"lang:default decode:true \">&lt;!-- ko text: getText() --&gt;&lt;!-- \/ko --&gt;<\/pre>\n<p>used for text output from functions, observed objects, etc.<\/p><\/li>\n<\/ol>\n<h2>What are the pros and cons of knockout templates<\/h2>\n<p>Knockout templates have the following advantages:<\/p>\n<ol>\n<li>Support for older browsers up to IE 6;<\/li>\n<li>Simple library;<\/li>\n<li>Separating HTML and JavaScript;<\/li>\n<li>Dynamic data binding.<\/li>\n<\/ol>\n<p>However, knockout templates have certain disadvantages:<\/p>\n<ol>\n<li>Poor performance if many objects;<\/li>\n<li>Magento switches to PWA, uses React, and Knockout will sooner or later become deprecated.<\/li>\n<\/ol>\n<h2>FAQ: Compare knockout templates with underscore JavaScript templates<\/h2>\n<ol>\n<li>Underscore template is rendered only when the method _.template (template) (params) is called, while Knockout template is automatically re-rendered if data changes.<\/li>\n<li>Underscore uses &lt;% = &hellip;%&gt;, &lt;% &hellip;%&gt;, &lt;% &ndash; &hellip;%&gt; blocks to execute scripts. Knockout uses the data-bind attribute in html elements and html comments.<\/li>\n<\/ol>\n<h2>Wrapping it up<\/h2>\n<p>This was the article about the knockout framework and how to work with it in Magento 2. If you have any questions or comments, feel free to leave them down below.<\/p>\n\n","protected":false},"excerpt":{"rendered":"Knockout.js &#8212; is a library that allows you to create dynamic interfaces and use different &#8230;","protected":false},"author":82,"featured_media":21158,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"image","meta":{"_acf_changed":false,"footnotes":""},"categories":[14,491,389,469,471,473],"tags":[],"class_list":["post-20774","post","type-post","status-publish","format-image","has-post-thumbnail","hentry","category-magento","category-magento-2","category-magento2-development","category-magento2-tutorial","category-magento-developer","category-magento-front-end-developer","post_format-post-format-image"],"acf":[],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.4 - aioseo.com -->\n\t<meta name=\"description\" content=\"Knockout.js is a library used for creation of dynamic interfaces and bindings for DOM elements. Find out more about knockout framework in this tutorial.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Andrey Litvin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/belvg.com\/blog\/what-is-knockout-js-framework.html\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.4\" \/>\n\t\t<script type=\"application\/ld+json\" class=\"aioseo-schema\">\n\t\t\t{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/what-is-knockout-js-framework.html#article\",\"name\":\"What is knockout js framework in Magento 2? | BelVG Blog\",\"headline\":\"What is Knockout JS Framework in Magento 2?\",\"author\":{\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/author\\\/andrey-litvin#author\"},\"publisher\":{\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/#organization\"},\"image\":{\"@type\":\"ImageObject\",\"url\":\"https:\\\/\\\/belvg.com\\\/blog\\\/wp-content\\\/uploads\\\/2019\\\/03\\\/Online-shop-of-High-tech-devices.png\",\"width\":1110,\"height\":591,\"caption\":\"Understanding knockout framework\"},\"datePublished\":\"2019-03-28T14:59:43+02:00\",\"dateModified\":\"2023-10-13T16:10:34+02:00\",\"inLanguage\":\"en-US\",\"commentCount\":1,\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/what-is-knockout-js-framework.html#webpage\"},\"isPartOf\":{\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/what-is-knockout-js-framework.html#webpage\"},\"articleSection\":\"Magento, Magento 2, Magento 2 Development, Magento 2 Tutorial, Magento Developer, Magento Front End Developer, Image\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/what-is-knockout-js-framework.html#breadcrumblist\",\"itemListElement\":[{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/#listItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/belvg.com\\\/blog\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/category\\\/magento#listItem\",\"name\":\"Magento\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/category\\\/magento#listItem\",\"position\":2,\"name\":\"Magento\",\"item\":\"https:\\\/\\\/belvg.com\\\/blog\\\/category\\\/magento\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/what-is-knockout-js-framework.html#listItem\",\"name\":\"What is Knockout JS Framework in Magento 2?\"},\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/#listItem\",\"name\":\"Home\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/what-is-knockout-js-framework.html#listItem\",\"position\":3,\"name\":\"What is Knockout JS Framework in Magento 2?\",\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/category\\\/magento#listItem\",\"name\":\"Magento\"}}]},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/#organization\",\"name\":\"BelVG Blog\",\"description\":\"Magento and Prestashop articles\",\"url\":\"https:\\\/\\\/belvg.com\\\/blog\\\/\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/author\\\/andrey-litvin#author\",\"url\":\"https:\\\/\\\/belvg.com\\\/blog\\\/author\\\/andrey-litvin\",\"name\":\"Andrey Litvin\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/what-is-knockout-js-framework.html#authorImage\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/e1a6e3c80cb940fddb65016d94b015cd951b4a8a9cd7227565131f28ea95c7a0?s=96&d=mm&r=g\",\"width\":96,\"height\":96,\"caption\":\"Andrey Litvin\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/what-is-knockout-js-framework.html#webpage\",\"url\":\"https:\\\/\\\/belvg.com\\\/blog\\\/what-is-knockout-js-framework.html\",\"name\":\"What is knockout js framework in Magento 2? | BelVG Blog\",\"description\":\"Knockout.js is a library used for creation of dynamic interfaces and bindings for DOM elements. Find out more about knockout framework in this tutorial.\",\"inLanguage\":\"en-US\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/#website\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/what-is-knockout-js-framework.html#breadcrumblist\"},\"author\":{\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/author\\\/andrey-litvin#author\"},\"creator\":{\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/author\\\/andrey-litvin#author\"},\"image\":{\"@type\":\"ImageObject\",\"url\":\"https:\\\/\\\/belvg.com\\\/blog\\\/wp-content\\\/uploads\\\/2019\\\/03\\\/Online-shop-of-High-tech-devices.png\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/what-is-knockout-js-framework.html\\\/#mainImage\",\"width\":1110,\"height\":591,\"caption\":\"Understanding knockout framework\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/what-is-knockout-js-framework.html#mainImage\"},\"datePublished\":\"2019-03-28T14:59:43+02:00\",\"dateModified\":\"2023-10-13T16:10:34+02:00\"},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/belvg.com\\\/blog\\\/\",\"name\":\"BelVG Blog\",\"description\":\"Magento and Prestashop articles\",\"inLanguage\":\"en-US\",\"publisher\":{\"@id\":\"https:\\\/\\\/belvg.com\\\/blog\\\/#organization\"}}]}\n\t\t<\/script>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"What is knockout js framework in Magento 2? | BelVG Blog","description":"Knockout.js is a library used for creation of dynamic interfaces and bindings for DOM elements. Find out more about knockout framework in this tutorial.","canonical_url":"https:\/\/belvg.com\/blog\/what-is-knockout-js-framework.html","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/belvg.com\/blog\/what-is-knockout-js-framework.html#article","name":"What is knockout js framework in Magento 2? | BelVG Blog","headline":"What is Knockout JS Framework in Magento 2?","author":{"@id":"https:\/\/belvg.com\/blog\/author\/andrey-litvin#author"},"publisher":{"@id":"https:\/\/belvg.com\/blog\/#organization"},"image":{"@type":"ImageObject","url":"https:\/\/belvg.com\/blog\/wp-content\/uploads\/2019\/03\/Online-shop-of-High-tech-devices.png","width":1110,"height":591,"caption":"Understanding knockout framework"},"datePublished":"2019-03-28T14:59:43+02:00","dateModified":"2023-10-13T16:10:34+02:00","inLanguage":"en-US","commentCount":1,"mainEntityOfPage":{"@id":"https:\/\/belvg.com\/blog\/what-is-knockout-js-framework.html#webpage"},"isPartOf":{"@id":"https:\/\/belvg.com\/blog\/what-is-knockout-js-framework.html#webpage"},"articleSection":"Magento, Magento 2, Magento 2 Development, Magento 2 Tutorial, Magento Developer, Magento Front End Developer, Image"},{"@type":"BreadcrumbList","@id":"https:\/\/belvg.com\/blog\/what-is-knockout-js-framework.html#breadcrumblist","itemListElement":[{"@type":"ListItem","@id":"https:\/\/belvg.com\/blog\/#listItem","position":1,"name":"Home","item":"https:\/\/belvg.com\/blog\/","nextItem":{"@type":"ListItem","@id":"https:\/\/belvg.com\/blog\/category\/magento#listItem","name":"Magento"}},{"@type":"ListItem","@id":"https:\/\/belvg.com\/blog\/category\/magento#listItem","position":2,"name":"Magento","item":"https:\/\/belvg.com\/blog\/category\/magento","nextItem":{"@type":"ListItem","@id":"https:\/\/belvg.com\/blog\/what-is-knockout-js-framework.html#listItem","name":"What is Knockout JS Framework in Magento 2?"},"previousItem":{"@type":"ListItem","@id":"https:\/\/belvg.com\/blog\/#listItem","name":"Home"}},{"@type":"ListItem","@id":"https:\/\/belvg.com\/blog\/what-is-knockout-js-framework.html#listItem","position":3,"name":"What is Knockout JS Framework in Magento 2?","previousItem":{"@type":"ListItem","@id":"https:\/\/belvg.com\/blog\/category\/magento#listItem","name":"Magento"}}]},{"@type":"Organization","@id":"https:\/\/belvg.com\/blog\/#organization","name":"BelVG Blog","description":"Magento and Prestashop articles","url":"https:\/\/belvg.com\/blog\/"},{"@type":"Person","@id":"https:\/\/belvg.com\/blog\/author\/andrey-litvin#author","url":"https:\/\/belvg.com\/blog\/author\/andrey-litvin","name":"Andrey Litvin","image":{"@type":"ImageObject","@id":"https:\/\/belvg.com\/blog\/what-is-knockout-js-framework.html#authorImage","url":"https:\/\/secure.gravatar.com\/avatar\/e1a6e3c80cb940fddb65016d94b015cd951b4a8a9cd7227565131f28ea95c7a0?s=96&d=mm&r=g","width":96,"height":96,"caption":"Andrey Litvin"}},{"@type":"WebPage","@id":"https:\/\/belvg.com\/blog\/what-is-knockout-js-framework.html#webpage","url":"https:\/\/belvg.com\/blog\/what-is-knockout-js-framework.html","name":"What is knockout js framework in Magento 2? | BelVG Blog","description":"Knockout.js is a library used for creation of dynamic interfaces and bindings for DOM elements. Find out more about knockout framework in this tutorial.","inLanguage":"en-US","isPartOf":{"@id":"https:\/\/belvg.com\/blog\/#website"},"breadcrumb":{"@id":"https:\/\/belvg.com\/blog\/what-is-knockout-js-framework.html#breadcrumblist"},"author":{"@id":"https:\/\/belvg.com\/blog\/author\/andrey-litvin#author"},"creator":{"@id":"https:\/\/belvg.com\/blog\/author\/andrey-litvin#author"},"image":{"@type":"ImageObject","url":"https:\/\/belvg.com\/blog\/wp-content\/uploads\/2019\/03\/Online-shop-of-High-tech-devices.png","@id":"https:\/\/belvg.com\/blog\/what-is-knockout-js-framework.html\/#mainImage","width":1110,"height":591,"caption":"Understanding knockout framework"},"primaryImageOfPage":{"@id":"https:\/\/belvg.com\/blog\/what-is-knockout-js-framework.html#mainImage"},"datePublished":"2019-03-28T14:59:43+02:00","dateModified":"2023-10-13T16:10:34+02:00"},{"@type":"WebSite","@id":"https:\/\/belvg.com\/blog\/#website","url":"https:\/\/belvg.com\/blog\/","name":"BelVG Blog","description":"Magento and Prestashop articles","inLanguage":"en-US","publisher":{"@id":"https:\/\/belvg.com\/blog\/#organization"}}]}},"aioseo_meta_data":{"post_id":"20774","title":"What is knockout js framework in Magento 2? | #site_title","description":"Knockout.js is a library used for creation of dynamic interfaces and bindings for DOM elements. Find out more about knockout framework in this tutorial.","keywords":null,"keyphrases":null,"focus_keyword":null,"additional_keywords":null,"truseo_locale":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_custom_url":null,"og_image_custom_fields":null,"og_image_url":null,"og_image_width":null,"og_image_height":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_image_url":null,"twitter_title":null,"twitter_description":null,"schema_type":"default","schema_type_options":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"limit_modified_date":false,"ai":null,"breadcrumb_settings":null,"seo_analyzer_scan_date":null,"created":"2026-11-03 18:36:50","updated":"2026-11-03 18:36:50"},"aioseo_breadcrumb":"<div class=\"aioseo-breadcrumbs\"><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/belvg.com\/blog\/\" title=\"Home\">Home<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">\u00bb<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/belvg.com\/blog\/category\/magento\" title=\"Magento\">Magento<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">\u00bb<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\tWhat is Knockout JS Framework in Magento 2?\n\t\t<\/span><\/div>","aioseo_breadcrumb_json":[{"label":"Home","link":"https:\/\/belvg.com\/blog\/"},{"label":"Magento","link":"https:\/\/belvg.com\/blog\/category\/magento"},{"label":"What is Knockout JS Framework in Magento 2?","link":"https:\/\/belvg.com\/blog\/what-is-knockout-js-framework.html"}],"post_mailing_queue_ids":[],"_links":{"self":[{"href":"https:\/\/belvg.com\/blog\/wp-json\/wp\/v2\/posts\/20774","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/belvg.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/belvg.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/belvg.com\/blog\/wp-json\/wp\/v2\/users\/82"}],"replies":[{"embeddable":true,"href":"https:\/\/belvg.com\/blog\/wp-json\/wp\/v2\/comments?post=20774"}],"version-history":[{"count":2,"href":"https:\/\/belvg.com\/blog\/wp-json\/wp\/v2\/posts\/20774\/revisions"}],"predecessor-version":[{"id":27500,"href":"https:\/\/belvg.com\/blog\/wp-json\/wp\/v2\/posts\/20774\/revisions\/27500"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/belvg.com\/blog\/wp-json\/wp\/v2\/media\/21158"}],"wp:attachment":[{"href":"https:\/\/belvg.com\/blog\/wp-json\/wp\/v2\/media?parent=20774"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/belvg.com\/blog\/wp-json\/wp\/v2\/categories?post=20774"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/belvg.com\/blog\/wp-json\/wp\/v2\/tags?post=20774"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}