I am new on Knockout.js, especially on how to use it in the Magento way.
I create a custom ViewModel with a js file called storepickup-select.js and an HTML template called storepickup-select.html.
I override Magento_Checkout/js/view/shipping on a custom shipping.js file on my custom module. In this file, I added two functions: selectedCarrierCode and saveStoreAddress.
When I call selectedCarrierCode on storepickup-select.html using the $parent variable, it works fine and without any problem:
<form class="form form-shipping-storepickup" id="co-storepickup-form" data-bind="visible: $parent.selectedCarrierCode()">
...
</form>
But when I tried to call saveStoreAddress from storepickup-select.js, it throws me an error:
selectStore: function(){
...
$parent.saveStoreAddress(addresData);
...
}
ReferenceError: $parent is not defined
I tried some other options:
parent
this.parent
this.$parent
But it doesn´t work. Why I can use $parent on HTML file but I can´t use it on js file? And, what is the better way to call saveStoreAddress from js file?
Thanks.
EDIT:
I added my js files:
shipping.js
define([
'jquery',
'underscore',
'Magento_Ui/js/form/form',
'ko',
'Magento_Customer/js/model/customer',
'Magento_Customer/js/model/address-list',
'Magento_Checkout/js/model/address-converter',
'Magento_Checkout/js/model/quote',
'Magento_Checkout/js/action/create-shipping-address',
'Magento_Checkout/js/action/select-shipping-address',
'Magento_Checkout/js/model/shipping-rates-validator',
'Magento_Checkout/js/model/shipping-address/form-popup-state',
'Magento_Checkout/js/model/shipping-service',
'Magento_Checkout/js/action/select-shipping-method',
'Magento_Checkout/js/model/shipping-rate-registry',
'Magento_Checkout/js/action/set-shipping-information',
'Magento_Checkout/js/model/step-navigator',
'Magento_Ui/js/modal/modal',
'Magento_Checkout/js/model/checkout-data-resolver',
'Magento_Checkout/js/checkout-data',
'uiRegistry',
'mage/translate',
'Magento_Checkout/js/model/shipping-rate-service'
], function (
$,
_,
Component,
ko,
customer,
addressList,
addressConverter,
quote,
createShippingAddress,
selectShippingAddress,
shippingRatesValidator,
formPopUpState,
shippingService,
selectShippingMethodAction,
rateRegistry,
setShippingInformationAction,
stepNavigator,
modal,
checkoutDataResolver,
checkoutData,
registry,
$t
) {
'use strict';
var mixin = {
selectShippingMethod: function (shippingMethod) {
selectShippingMethodAction(shippingMethod);
checkoutData.setSelectedShippingRate(shippingMethod.carrier_code + '_' + shippingMethod.method_code);
return true;
},
selectedCarrierCode: ko.computed(function() {
var method = quote.shippingMethod();
var selectedCarrierCode = (method != null) ? method.carrier_code : null;
return selectedCarrierCode;
}),
saveStoreAddress: function (addressData) {
addressData['save_in_address_book'] = 0;
console.log(addressData);
newShippingAddress = createShippingAddress(addressData);
selectShippingAddress(newShippingAddress);
checkoutData.setSelectedShippingAddress(newShippingAddress.getKey());
checkoutData.setNewCustomerShippingAddress($.extend(true, {}, addressData));
//this.getPopUp().closeModal();
this.isNewAddressAdded(true);
}
};
return function (target) {
return target.extend(mixin);
};
});
storepickup-select.js
define([
'jquery',
'ko',
'mage/url',
'uiComponent',
'Magento_Checkout/js/model/quote'
], function ($, ko, url, Component, quote) {
'use strict';
return Component.extend({
defaults: {
template: 'Morwi_Checkout/checkout/shipping-address/storepickup-select.html'
},
/** @inheritdoc */
initialize: function (){
this._super();
this.bindAvailableStores();
this.bindSelectedStore();
},
storeDetailUrl: ko.observable(),
availableStores: ko.observableArray([]),
storeAddress: [],
selectedStore: ko.observable(),
bindAvailableStores: function(){
console.log('bindAvailableStores');
var element = this;
$.ajax({
url: url.build('recogertienda/stores/get'),
type: 'post',
contentType: 'application/json',
async: false,
success: function(response){
element.setAvailableStores(response)
for(var index in response){
element.storeAddress[response[index].id] = response[index].address;
}
console.log(element.storeAddress);
}
});
},
bindSelectedStore: function(){
console.log('bindSelectedStore');
var element = this;
$.ajax({
url: url.build('recogertienda/stores/selected'),
type: 'post',
contentType: 'application/json',
async: false,
success: function(response){
if(response.id != 0){
element.setSelectedStore(response.id);
}
else{
element.setSelectedStore('');
}
element.selectStore();
}
});
},
setAvailableStores(data){
this.availableStores(data);
},
setSelectedStore(data){
this.selectedStore(data);
},
selectStore: function(){
if((typeof this.selectedStore() !== 'undefined') && (this.selectedStore() != '')){
this.storeDetailUrl(url.build('storelocator/index/view/id/' + this.selectedStore().toString()));
$parent.saveStoreAddress(this.storeAddress[this.selectedStore()]);
}
else{
this.storeDetailUrl(url.build('storelocator'));
}
}
});
}
);
Best Answer
You don't need to call $parent in js, just call your function directly using
this.functionName()
.EDIT (Some context) :
You call
$parent
in your case to refer to js file associated with HTML template in/js/view/..
i.e the view model.