Magento2 UI Components – Clear Billing Form Validation Errors

billing-addresscheckoutmagento2

Default magento checkout behavior when using new customer billing address form (related to newCustomerBillingAddress name in the local storage).

enter image description here

  1. we uncheck "My billing and shipping address are the same" checkbox
  2. the new customer billing address form is shown
  3. we start to fill some data into the fields. for example "first name".
  4. we remove this "first name" value and we see validation error
  5. we click again "cancel" at the bottom or the checkbox "my billing and shipping address are the same"
  6. form is hidden
  7. we uncheck the "my billing and shipping address are the same"
  8. we see the form and the validation errors

My questions are related to step nr 7 and 8.

Q1: how to clear validation errors in the form when action in step 7 happens and we see form (step 8) ? How to do it when we show form using our custom functions to show/hide form and select different addresses (when user is logged) ? I would like example of function that I could put into view/billing-address.js that will clear validation error in/after step nr 8.

Q2: Why if user click "cancel" magento saves the changed input values? I guess it's because keyUp event in Magento Ui?

I've made some changes that if:

p1. user fill the form and click "save". data is valid so store in some observable/localStorage

p2. user edits the form data. Ex. He removes the first name field.. but than he clicks cancel button

in p2 step I compare previous valid form data to the new form data.

If the field has different value than I restore the valid one and I have to trigger keyUp for fields that were modified to hide the validation error.

I know I do it the wrong way… but how can I access in billing-address.js every billing address form's field (to set new value / clear validation / revalidate) ?

extra question – why magento2 knockout's billing-address.js methods are executed in every payment method scope (this.dataScopePrefix) even if we turn on in store only one or two or X payment methods?

Best Answer

You've asked a bit of a mouthful there -- probably too much for a single Stack Exchange question, so I'm going to concentrate on teaching you how to reset the initial state of the form so things no longer appear invalid if there's a blank value. If you're interested in the whys, you'll need to get up to speed on the fundamentals of UI Components and x-magento-init scripts. My Magento 2 UI Components and uiElement Internals series are a good place to start. The following assumes you have some familiarity with these systems -- if there's something confusing below then the above articles (as well as the other Magento 2 articles) will probably have the information you're looking for.

In the Checkout Application, each form field is represented by a view model, and one-or-many view model templates. You can see this in Commerce Bug's KO Scopes tab.

enter image description here

The firstname's view model is an object derived from the constructor function returned by the Magento_Ui/js/form/element/abstract RequireJS module. You can find that model's source code here

vendor/magento//module-ui/view/base/web/js/form/element/abstract.js

The reset method is the one we're interested in. This will reset a field's validation state. You'll need to figure out the full uiRegistry string identifier for the specific model (again, Commerce Bug is useful here), use that string to fetch the instantiated view model, and then call the reset function. For the checkmo form, the following program (easily adapted into a define module if you're going to use it in your application) will do that for the firstname field.

requirejs(['uiRegistry'], function(uiRegistry){
    uiRegistry.get('checkout.steps.billing-step.payment.payments-list.checkmo-form.form-fields.firstname').reset();
});

Of course, you'll likely want to fetch each view model that's part of a particular form -- the following is a start on that.

uiRegistry.get(function(viewModel){
    var parentName = viewModel['parentName'] ? viewModel['parentName'] : '';
    if(parentName.indexOf('checkout.steps.billing-step.payment.payments-list.checkmo-form.form-fields') === -1){
        return;
    };       
    console.log(viewModel);
});

This uses the uiRegistry's callback feature to search for all view models with a parent of checkout.steps.billing-step.payment.payments-list.checkmo-form.form-fields. Some of these may not be form elements, but we'll leave that problem as an exercise for the questioner.

Hope that helps!

Related Topic