Allow subforms to have the context of the parent form state as-well.

CommentFileSizeAuthor
pass-parent-form-state.patch653 bytesamitaibu

Comments

casey’s picture

Not sure yet. When having multiple subforms, memory usage could become massive. Also subforms depending on parent's state will be minimal I reckon.

Maybe we should only pass parent's build id so if a subform needs parent state it can load it from cache.

amitaibu’s picture

> Maybe we should only pass parent's build id so if a subform needs parent state it can load it from cache.

Yes, sounds better

amitaibu’s picture

Status: Needs review » Needs work

I think that actually passing the form-build-id isn't enough, as it will be created only after form submit.

I wanted to add something like this in subform_element_process()

  // Pass information the parent has explicitly asked to pass.
  if (!empty($form_state['subform_cascade'])) {
    $subform_state['temporary']['subform_element_parents_cascade'] = $form_state['subform_cascade'];
  }

however, it seems not to pass.

The idea is that for example the wrapper form can pass $form_state['subform_cascase']['foo'] = 'bar'.
In turn, modules that for example implement hook_form_alter() can check those values, to get more context about the wrapping form.

casey’s picture

Right, but there would be an issue with ajax functionality in subforms.

If the subform contains an ajax button and that button is pressed, only the subform is processed. No subform_element_*() functions are called. So you won't have access to $form_state['temporary']['subform_element_parents_cascade'] in your subform. And I don't really like adding the parent state as a non-temporary; memory usage.

But parent's build_id is always accessible. So I added $subform_state['subform_parent']['form_id'] and $subform_state['subform_parent']['build_id']. And a new API function subform_get_parent_state($subform_state).

function mymodule_form_node_form_alter(&$form, &$form_state, $form_id) {
  // Detect if node form is used as a subform.
  //if (!empty($form_state['subform_name']) && $subform_state['subform_parent']['form_id'] == 'mymodule_parent_form') {
  if ($parent_state = subform_get_parent_state($form_state)) {
    ...
  }
}
casey’s picture

Also, you can already pass variables to a subform's state:

function mymodule_parent_form_{process|after_build}($form, &$form_state) {
  $subform_state = subform_get_state($form['my']['subform']['element'], $form_state);
  $subform_state['foo'] = $form_state['bar'];
}

Plus some still undocumented feature, you can override any #{property} from subform's form element. For example:

function mymodule_parent_form_{process|after_build}($form, &$form_state) {
  $subform_state = subform_get_state($form['my']['subform']['element'], $form_state);
  $subform_state['subform_properties']['attached']['js'] = drupal_get_path('module', 'mymodule') . '/mymodule.js';
}
amitaibu’s picture

Great addition!

maybe we should add a helper function to get the top most parent? (user-modal is currently doing it)

/**
 * Recursive helper function to get the top most parent.
 */
function user_modal_get_parent_state($form_state) {
  if (empty($form_state['subform_name'])) {
    return $form_state;
  }
  $parent_state = subform_get_parent_state($form_state);
  return user_modal_get_parent_state($parent_state);
}
amitaibu’s picture

btw, user-modal is now using the overlay to get the modal, instead of CTools' modal, and I've added a well-documented user-modal-example -- I think it can help devs better understanding how to use subforms.