2

The Problem:

I've implemented jQuery-ui Autocomplete with Knockout Js in Checkout Page but some input fields that are binded to my Component throw a validation error ("Required Field") when i update the input's value programmatically.

error

The Context:

I've asked already a question for the way of implementing the Autocomplete functionality but taking into account that the new problems are more specific i've posted this question. This is the link for the other one: Jquery-Ui Autocomplete with KnockoutJs Magento 2

The result 'till now is this: styles

What I've Done:

In Vendor/Module/Plugin/Checkout/Block/Checkout/LayoutProcessorPlugin.php

public function afterProcess(
 \Magento\Checkout\Block\Checkout\LayoutProcessor $subject,
 array $jsLayout
) {
 $departmentField = [
 'component' => 'Vendor_Module/js/shippingAutocomplete',
 'config' => [
 // customScope is used to group elements within a single form (e.g. they can be validated separately)
 'customScope' => 'shippingAddress',
 'template' => 'ui/form/field',
 'elementTmpl' => 'Vendor_Module/autocomplete/shippingAddress/regionInput',
 'id' => 'region',
 'tooltip' => [
 'description' => 'Select a Department',
 ],
 ],
 'dataScope' => 'shippingAddress.region',
 'label' => 'Department',
 'provider' => 'checkoutProvider',
 'sortOrder' => 51,
 'validation' => [
 'required-entry' => true
 ],
 'options' => [],
 'visible' => true,
 ];
 $jsLayout['components']['checkout']['children']['steps']['children']['shipping-step']['children']
 ['shippingAddress']['children']['shipping-address-fieldset']['children']['region'] = $departmentField;
 $departmentIdField = [
 'component' => 'Vendor_Module/js/shippingAutocomplete',
 'config' => [
 // customScope is used to group elements within a single form (e.g. they can be validated separately)
 'customScope' => 'shippingAddress',
 'template' => 'ui/form/field',
 'elementTmpl' => 'Vendor_Module/autocomplete/regionIdInput',
 'id' => 'region_id',
 ],
 'dataScope' => 'shippingAddress.region_id',
 'provider' => 'checkoutProvider',
 'sortOrder' => 50,
 'validation' => [
 'required-entry' => true
 ],
 'options' => [],
 'visible' => true,
 ];
 $jsLayout['components']['checkout']['children']['steps']['children']['shipping-step']['children']
 ['shippingAddress']['children']['shipping-address-fieldset']['children']['region_id'] = $departmentIdField;
 $cityField = [
 'component' => 'Vendor_Module/js/shippingAutocomplete',
 'config' => [
 // customScope is used to group elements within a single form (e.g. they can be validated separately)
 'customScope' => 'shippingAddress',
 'template' => 'ui/form/field',
 'elementTmpl' => 'Vendor_Module/autocomplete/shippingAddress/cityInput',
 'id' => 'city',
 'tooltip' => [
 'description' => 'Select a City.',
 ],
 ],
 'dataScope' => 'shippingAddress.city',
 'label' => 'City',
 'provider' => 'checkoutProvider',
 'sortOrder' => 53,
 'validation' => [
 'required-entry' => true
 ],
 'options' => [],
 'visible' => true,
 ];
 $jsLayout['components']['checkout']['children']['steps']['children']['shipping-step']['children']
 ['shippingAddress']['children']['shipping-address-fieldset']['children']['city'] = $cityField;
 $cityIdField = [
 'component' => 'Vendor_Module/js/shippingAutocomplete',
 'config' => [
 // customScope is used to group elements within a single form (e.g. they can be validated separately)
 'customScope' => 'shippingAddress',
 'template' => 'ui/form/field',
 'elementTmpl' => 'Vendor_Module/autocomplete/cityIdInput',
 'id' => 'city_id',
 ],
 'dataScope' => 'shippingAddress.city_id',
 'provider' => 'checkoutProvider',
 'sortOrder' => 52,
 'validation' => [
 'required-entry' => true
 ],
 'options' => [],
 'visible' => true,
 ];
 $jsLayout['components']['checkout']['children']['steps']['children']['shipping-step']['children']
 ['shippingAddress']['children']['shipping-address-fieldset']['children']['city_id'] = $cityIdField;
 $postcodeField = [
 'component' => 'Vendor_Module/js/shippingAutocomplete',
 'config' => [
 // customScope is used to group elements within a single form (e.g. they can be validated separately)
 'customScope' => 'shippingAddress',
 'template' => 'ui/form/field',
 'elementTmpl' => 'Vendor_Module/autocomplete/postcodeInput',
 'id' => 'postcode',
 ],
 'dataScope' => 'shippingAddress.postcode',
 'label' => 'Postal Code',
 'provider' => 'checkoutProvider',
 'sortOrder' => 54,
 'validation' => [
 'required-entry' => true
 ],
 'options' => [],
 'visible' => true,
 ];
 return $jsLayout;
}

My Vendor/Module/view/frontend/web/js/shippingAutocomplete.js looks like this:

define([
'Magento_Ui/js/form/element/abstract',
'mage/url',
'ko',
'jquery',
'jquery/ui'
], function (Abstract, url, ko, $) {
'use strict';
ko.bindingHandlers.shippingAutoComplete = {
 init: function (element, valueAccessor) {
 console.log("Init - Custom Binding Shipping");
 console.log(element);
 console.log(valueAccessor);
 // valueAccessor = { selected: mySelectedOptionObservable, options: myArrayOfLabelValuePairs }
 var settings = valueAccessor();
 var selectedOption = settings.selected;
 var options = settings.options;
 var updateElementValueWithLabel = function (event, ui) {
 // Stop the default behavior
 event.preventDefault();
 // Update the value of the html element with the label
 // of the activated option in the list (ui.item)
 $(element).val(ui.item.label);
 if (ui.item.type == 'city') {
 var cityId = $('[name="city_id"]');
 cityId.val(ui.item.value);
 var postcode = $('[name="region_id"]').val()+cityId.val();
 $('[name="postcode"]').val(postcode);
 } else if (ui.item.type == 'department') {
 $('[name="region_id"]').val(ui.item.value);
 }
 // Update our SelectedOption observable
 if(typeof ui.item !== "undefined") {
 // ui.item - id|label|...
 selectedOption(ui.item);
 //selectedValue(ui.item.value);
 }
 };
 $(element).autocomplete({
 source: options,
 select: function (event, ui) {
 updateElementValueWithLabel(event, ui);
 }
 });
 }
};
return Abstract.extend({
 selectedDepartment: ko.observable(''),
 selectedCity: ko.observable(''),
 postCode: ko.observable(''),
 getDepartments: function( request, response ) {
 $.ajax({
 url: url.build('list/check/departments/'),
 data: JSON.stringify({
 q: request.term
 }),
 contentType: "application/json",
 type: "POST",
 dataType: 'json',
 error : function () {
 alert("An error have occurred.");
 },
 success : function (data) {
 //Data is a string of the form: '[{"label": label, "value": value}]'
 var items = JSON.parse(data);
 response( items );
 }
 });
 },
 getCities: function( request, response ) {
 var departmentValue = $('[name="region"]').val();
 $.ajax({
 url: url.build('list/check/cities/'),
 data: JSON.stringify({
 q: request.term,
 filter: departmentValue
 }),
 contentType: "application/json",
 type: "POST",
 dataType: 'json',
 error : function () {
 alert("An error have occurred.");
 },
 success : function (data) {
 //Data is a string of the form: '[{"label": label, "value": value}]'
 var items = JSON.parse(data);
 response( items );
 }
 });
 }
});
});

The inputs are as follows:

In Vendor/Module/view/frontend/web/template/autocomplete/shippingAddress/regionInput.html

<input class="admin__control-text" type="text"
 data-bind="
 shippingAutoComplete: {
 selected: selectedDepartment,
 options: getDepartments
 },
 event: {change: userChanges},
 value: value,
 hasFocus: focused,
 valueUpdate: valueUpdate,
 attr: {
 name: inputName,
 placeholder: placeholder,
 'aria-describedby': noticeId,
 id: uid,
 disabled: disabled
}"/>

In Vendor/Module/view/frontend/web/template/autocomplete/shippingAddress/cityInput.html

<input class="admin__control-text" type="text"
 data-bind="
 shippingAutoComplete: {
 selected: selectedCity,
 options: getCities
 },
 event: {change: userChanges},
 value: value,
 hasFocus: focused,
 valueUpdate: valueUpdate,
 attr: {
 name: inputName,
 placeholder: placeholder,
 'aria-describedby': noticeId,
 id: uid,
 disabled: disabled
}"/>

In Vendor/Module/view/frontend/web/template/autocomplete/regionIdInput.html

<input class="admin__control-text"
 data-bind="
 value: value,
 hasFocus: focused,
 attr: {
 name: inputName,
 placeholder: placeholder,
 'aria-describedby': noticeId,
 id: uid
}"/>

In Vendor/Module/view/frontend/web/template/autocomplete/cityIdInput.html

<input class="admin__control-text"
 data-bind="
 value: value,
 hasFocus: focused,
 attr: {
 name: inputName,
 placeholder: placeholder,
 'aria-describedby': noticeId,
 id: uid
}"/>

In Vendor/Module/view/frontend/web/template/autocomplete/postcodeInput.html

<input class="admin__control-text" type="text"
 data-bind="
 event: {change: userChanges},
 value: value,
 hasFocus: focused,
 valueUpdate: valueUpdate,
 attr: {
 name: inputName,
 placeholder: placeholder,
 'aria-describedby': noticeId,
 id: uid,
 disabled: disabled
}"/>
asked Feb 14, 2017 at 15:15

2 Answers 2

0

Use

$('name=["postcode"]').trigger("change");

This will fix your validation problem.

General Grievance
4531 gold badge7 silver badges12 bronze badges
answered Nov 5, 2022 at 20:06
-1

Change directy the value of the knockout observable object from your custom input field.

Pass the observale in your data-bind attribute:

 shippingAutoComplete: {
 selected: selectedCity,
 options: getCities
 value: value // this is your obersable you wanna change
 },

Access it via

 var settings = valueAccessor();
 var inputValue= settings.value;

Change value

inputValue("yourValue");
answered Feb 27, 2019 at 15:10

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.