This might be a core issue, not sure yet how to properly fix this.

We used to implement the event and now the widget alter hook to set address default values based on fields on the logged in user. That worked fine for the first payment method. However, when you already have a stored payment method, for example with stripe, and then want to add a new one, the default values aren't there.

Took me quite some debugging but I tracked it down to some form ajax trickery that initializes the user input of all fields to NULL and then somehow that doesn't get overwritten with the actual fields.

It could be related to how the fields are created during process callbacks, so maybe for example date fields are affected in a similar way.

I found some existing issues which might the same issue, e.g. #3037289: On duplicated entities, field address is always empty or #2914208: Address field not keeping it's value when being edited inside an ief, which was closed as duplicate of the default value issue, but might actually have been this. I have been testing with the most recent version. Was actually hoping that would fix my problem, but it didn't :)

As a workaround, I did now this in my widget alter hook:


// Workaround for initializing an address field on ajax, which might have
  // its input values set to null.
  $input = $form_state->getUserInput();
  $address_input = &NestedArray::getValue($input, array_merge($element["#field_parents"], ['address', 0, 'address']));
  if (is_array($address_input) && array_key_exists('country_code', $address_input) && $address_input['country_code'] === NULL) {
    NestedArray::unsetValue($input, array_merge($element["#field_parents"], ['address', 0, 'address']));
    $form_state->setUserInput($input);
  }

Obviously not very pretty.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Berdir created an issue. See original summary.

drugan’s picture

I had the same issue with the commerce coupon ajax-fied pane. The reason is the invalid render key, like:

'24243535353' => NULL,

The fix is pretty the same: remove that key from the render array.

bojanz’s picture

Assigned: Unassigned » bojanz

Narrowed it down to this part of FormBuilder::handleInputElement:

        if (!$input_exists && !$form_state->isRebuilding() && !$form_state->isProgrammed()) {
          // Add the necessary parent keys to FormState::$input and sets the
          // element's input value to NULL.
          NestedArray::setValue($form_state->getUserInput(), $element['#parents'], NULL);
          $input_exists = TRUE;
        }

Input is processed twice (build then rebuild), the first time the address NULL value gets expanded into a an array with a NULL value for each address property, the second time that array makes Address::valueCallback() skip the default value.
We need a test. And we need to make Address::valueCallback() ignore inputs with NULL country codes (cause in reality it's never NULL, even on an optional field it's an empty string when nothing is selected).

bojanz’s picture

Title: Address default values are not working in fields added through ajax » The address default value isn't always shown when ajax is used
bojanz’s picture

Assigned: bojanz » Unassigned
Status: Active » Needs review
FileSize
7.52 KB

Here's a fix and a test.

Confirmed that the new test fails without the fix.
Confirmed that Commerce checkout works well with the fix.
Added Commerce specific test coverage in #3022850: [Addressbook, part 1] Rework the ownership model for customer profiles.

  • bojanz committed 0bcd550 on 8.x-1.x
    Issue #3047340 by bojanz, Berdir: The address default value isn't always...
bojanz’s picture

Status: Needs review » Fixed

Committed.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.