Possible to access form_state values from previous steps?

Created on 28 August 2023, 10 months ago
Updated 30 August 2023, 10 months ago

I'm trying to pre-populate a later step field using a previous step field value in a form alter hook.

It seems I can only access partial form state values using $form_state->getValues();

I tried to use setTemporaryValue but that doesn't seem to persist either.

Is there a way that I can access the entire submitted form values during the steps?

πŸ’¬ Support request
Status

Closed: works as designed

Version

1.1

Component

Code

Created by

πŸ‡ΊπŸ‡ΈUnited States jimmynash

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @jimmynash
  • Status changed to Postponed: needs info 10 months ago
  • πŸ‡ΊπŸ‡ΈUnited States robphillips

    Are you trying to do this using a form alter or one of the modules API hooks? https://git.drupalcode.org/project/entity_form_steps/-/blob/1.x/entity_f...

    You might consider using the entity builder to get a value instead of form state. Something like:

    $entity = $form_state->getFormObject()->getEntity();
    $form_state->setValue('field_two', $entity->get('field_one')->getValue());
    

    How you're implementing the alter does make a difference. If you can provide code examples I might be able to help further. This module does not change the default behavior of Drupal form states. It only sets the #access property on elements not in the current step.

  • πŸ‡ΊπŸ‡ΈUnited States jimmynash

    Thanks for the reply and example!

    I have been using just a normal hook_form_formid_alter and was trying to use $form_state->getValues() to get what I needed but each time I would dump those values to look at them I just had the values from the step previous.

    This is generally what I was trying to do. An address field provided earlier in the form should be pre-filled into a paragraph at the end of the form.
    I haven't gotten to seeing if the paragraph stuff works yet as I was having trouble getting the previous address to use.

    Basically this:

    /**
     * Used to alter the entire form
     * Implements hook_form_FORMID_alter()
     */
    function MYMODULE_form_FORMID_alter(&$form, FormStateInterface $form_state, $form_id) {
    
      if( $steps && ($steps['current_step'] == 'group_locations') ) {
        $addr = $form_state->getValues('field_address');
        $paragraph = Paragraph::create([
          'type' => 'location',  // paragraph type machine name
          'field_address2' => $addr,
        ]);
    
        $form_state->setValue('field_locations', $paragraph);
      }
    
    }
    

    So should I be using the provided api hook to do any form altering from my modules?
    hook_entity_form_steps_complete_form_alter

    Maybe you could tell me if I'm generally right in these assumptions:

    hook_entity_form_steps_complete_form_alter is for altering entity forms under entity_form_steps control.

    hook_entity_form_steps_state_alter is for altering what step the user is on

    hook_entity_form_steps_alter is for altering the steps themselves such as button labels etc that are set in the field group configurations.

    Do I have that right?

  • πŸ‡ΊπŸ‡ΈUnited States robphillips

    Your assumptions are correct. The hook_entity_form_steps_complete_form_alter hook is invoked very last. After the form step changes have been completely applied. Implementing hook_form_FORM_ID_alter doesn't guarantee the form steps availability in the form alter. See https://git.drupalcode.org/project/entity_form_steps/-/blob/1.x/entity_f....

    Here's an untested example:

    function hook_entity_form_steps_complete_form_alter(array &$form, FormStateInterface $form_state, FieldableEntityInterface $entity, array $state) {
      if ($state['current_step'] === 'group_locations') {
        $paragraph = Paragraph::create([
          'type' => 'location',
          'field_address2' => $entity->get('field_address')->getValue(),
        ]);
        $form_state->setValue('field_locations', $paragraph);
      }
    }
    
  • πŸ‡ΊπŸ‡ΈUnited States jimmynash

    Well, the paragraph part is being rather stubborn. At least, setting it on the main entity form.

    I can create it and I can access the previous address field now using the complete_form_alter api hook.
    But it just won't show as part of the form when I try and use

    $form_state->setValue('field_locations', $paragraph);

    I've tried with the form field config set to have a default location paragraph and without. My goal is to have an editable, prefilled paragraph sitting there at that step for the user to accept or modify before moving on.

    I tried setting it on the entity as well and that seems to do nothing either. Even finishing the form, neither ends up adding this paragraph to the node.

    I feel like this is a paragraphs thing but I can't be sure.

    I'll keep trying and post back if I get it.

  • πŸ‡ΊπŸ‡ΈUnited States robphillips

    If you're trying to set a default value on the paragraph it needs to be set differently. Using $form_state->setValue('field_locations', $paragraph); is only suitable if the paragraph field itself is not part of the form display. Otherwise it's value is overridden when the rendered paragraph subform is submitted.

    You might be able to adapt this example to your needs: https://www.drupal.org/forum/support/module-development-and-code-questio... β†’

    The key is setting #default_value on the paragraph field within the paragraph subform.

  • Status changed to Closed: works as designed 10 months ago
  • πŸ‡ΊπŸ‡ΈUnited States jimmynash

    Sorry that this strayed a little from the purpose of the module but your assistance has been invaluable.

    The example you sent put me on the right path and now I do get a prefilled paragraph that the user can alter if needed before moving on from that step. The key was that hook_field_widget_paragraphs_form_alter.

    By using the entity builder you mentioned I'm able to look for the existence of the previous field value and set that address as the #default_value on the paragraph subform address.

    /**
     * Implements hook_field_widget_WIDGET_TYPE_form_alter().
     */
    function MYMODULE_field_widget_paragraphs_form_alter(&$element, &$form_state, $context) {
      if ($element['#paragraph_type'] == 'location') {
    
        $entity = $form_state->getFormObject()->getEntity();
        $ins_addr = $entity->get('field_insured_address')->getValue()[0];
    
        if( $ins_addr['address_line1'] ) {
          $element['subform']['field_address']['widget'][0]['address']['#default_value'] = $ins_addr;
        }
      }
    }
    

    Super huge kudos @robphillips!

Production build 0.69.0 2024