The Magento_Ui/js/lib/ko/initialize
library is, indeed, where Magento initializes its Knockout instance. Magento does not assign a ViewModel when it applies bindings.
The missing key here is the custom KnockoutJS binding named scope
.
When Magento's Knockout instance encounters a scope:
binding like this
<li class="greet welcome" data-bind="scope: 'customer'">
<span data-bind="text: customer().fullname ? $t('Welcome, %1!').replace('%1', customer().fullname) : 'Default welcome msg!'"></span>
</li>
It takes the value of that binding (named customer
), and uses it to load and apply a ViewModel for the inner nodes from the uiRegistry
. You can debug the data bound for a particular scope with some simple KnockoutJS pre
debugging
<div data-bind="scope: 'someScope'">
<pre data-bind="text: ko.toJSON($data, null, 2)"></pre>
</div>
The uiRegistry
is a simple dictionary like object, implemented in the Magento_Ui/js/lib/registry/registry
RequireJS module.
vendor/magento/module-ui/view/base/requirejs-config.js
17: uiRegistry: 'Magento_Ui/js/lib/registry/registry',
Objects are put into the registry via the bits of javascript that look like this
<script type="text/x-magento-init">
{
"*": {
"Magento_Ui/js/core/app": {
"components": {
"customer": {
"component": "Magento_Customer/js/view/customer",
"extra_data_1":"some_value",
"more_extra":"some_other_value",
}
}
}
}
}
</script>
The program in the Magento_Ui/js/core/app
module will examine the components
key of the passed in object, and for each sub-object will
Fetch the object returned by the specified RequireJS
module from the component
key (Magento_Customer/js/view/customer
)
Use that object to instantiate a new javascript object (see below)
Assign any extra data keys to that same object
Add that same object to the uiRegistry
with the key of the original object (customer
above)
If you're not sure how the x-magento-init
script works, I've written an article about it here.
There's a more in depth examination of the app.js
process over in this answer.
The implementation of the scope binding is defined here
vendor/magento//module-ui/view/base/web/js/lib/ko/bind/scope.js
Change requirejs-config.js following way:
Vendor/Module/view/adminhtml/requirejs-config.js
var config = {
"map": {
"*": {
"Magento_ConfigurableProduct/js/variations/steps/summary": "Vendor_Module/js/variations/steps/summary-custom",
}
}
}
Now create summary-custom.js file [Vendor/Module/view/adminhtml/web/js/variations/steps/summary-custom.js]
define([
'uiComponent',
'jquery',
'ko',
'underscore',
'mage/translate',
'Magento_ConfigurableProduct/js/variations/steps/summary'
], function (Component, $, ko, _,$t,summary) {
'use strict';
});
Run following command and clear cache.
php bin/magento setup:static-content:deploy
Best Answer
The choice of which of those techniques to use is often relative and can be decided by general principles. There are a few exceptions when a mixin would not accomplish the goal and therefore,
map
must be used.TL;DR
map
if a mixin won't work or if the file is being changed extensively.Definitions:
Generally speaking, a mixin overrides individual methods inside of a Javascript object (or "class").
A
map
is a key used inrequirejs-config.js
that can replace one file with another. This overrides an entire file. Themes have the capability of doing this withoutrequirejs-config.js
.General Principles / Best Practice
Now, what general principles should we use when making the decision of which approach to use? Relative to this question, I suggest the following:
This isn't really the only one, though. Other considerations include overall development time, simplicity of the code in question, and probably more.
The benefit of affecting as little code as possible is upgradability and maintainability. If the core file changes, there is a smaller chance of it breaking your update. In addition, since there is less code there altogether, bug fixes or changes to it should be easier.
Specific to your question:
A mixin is a great choice because it affects very little code and is easy to implement. If you were to use
map
, you would have to copy and override the entire file. You can't extend the original file like you would with PHP because referencing the original file would load your own file.With regards to your mixin question:
target
is the original Javascript object. Magento's mixin handler provides that to you. Further, your mixin must match the structure of the original Javascript object: whether an object or jQuery UI widget or other. This necessitates some slightly awkward code at times.The code in your example is correct: Magento merges your object over the top of the original one. This replaces the original
initialize
method with your method but keeps the rest of the object intact.