Import form values from one form to another via AJAX

Drupal 7's new and improved Form API makes using AJAX a breeze. It enables you to add, replace, or remove form elements via AJAX without ever really having to get your hands dirty.

I recently had the opportunity to give it a whirl. Here's a the deal:
I have content type Resume and Profile2 type Job Seeker Profile. I'd like my users to be able to create up to 5 resumes, and I'd like them to have the option of importing information from their profile into their brand-spanking new resume. So, I'm going to create an 'Import from profile' button that will populate the resume fields with profile field values via AJAX.

Note: It is possible to accomplish something like this by setting default values via a token. However, in this case, I'd like to be able to import things like field collections, addresses, and fields with unlimited cardinality. Here's the code that accomplished it!

/**
 * Implements hook_form_FORM_ID_alter().
 * Resume node form.
 */
function grasmash_form_resume_node_form_alter(&$form, &$form_state, $form_id) {
  // Load user's current profile.
  $uid = $form['uid']['#value'];
  $author = user_load($uid );
  $profile = profile2_load_by_user($author, 'seeker_profile');
 
  // Add button permitting users to import Work Experience from their Profile.
  if (array_key_exists('und', $profile->field_work_experience)) { // It's good to first check that there's actually something to import.
    // Wrapping the element with HTML lets us easily define the scope of the AJAX replacement later.
    $form['field_work_experience']['#prefix'] = '<div id="field-work-experience-wrapper">';
    $form['field_work_experience']['#suffix'] = '</div>';
 
    $form['field_work_experience']['import_work_experience'] = array(
      '#type' => 'submit',
      '#value' => 'Import work experience from your profile',
      '#description' => t('This will overwrite anything you have entered into the Work Experience field!'),
      '#weight' => -20,
      '#attributes' => array('class' => array('field-add-more-submit')),
      '#limit_validation_errors' => array(), // Don't validate when the button is clicked!
      '#ajax' => array(
        'callback' => 'grasmash_js_import_work_experience',
        'wrapper' => 'field-work-experience-wrapper',
        'effect' => 'fade',
        'method' => 'replace',
      ),
    );
  }
}
 
/* 
 * Define AJAX return functions for Work Experience field.
 */
function grasmash_js_import_work_experience($form, $form_state) {
  $field_collection = 'field_work_experience';
  // Load the correct field collection using another function. This approach allows us to easily repeat this process with another field collection if desired.
  $element = grasmash_js_import_field_collection($field_collection, $form, $form_state);
  return $element;
}
 
/* 
 * Import pre-populated field_collection form element from a user's job seeker profile.
 */
function grasmash_js_import_field_collection($field_collection, &$form, &$form_state) {
 
  // Load author profile if necessary.
  $uid = $form['uid']['#value'];
  $author = user_load($uid);
 
  //module_load_include('inc', 'profile2_page', 'profile2_page'); // loading with hook_init instead
  $profile2 = profile2_by_uid_load($uid, 'seeker_profile');
  $profile2_form = entity_ui_get_form('profile2', $profile2, 'edit');
 
  if (isset($profile2_form)) {
    // Pull in corresponding form element from profile form.
    $element = $profile2_form['profile_seeker_profile'][$field_collection];
 
    // Process the imported element.
    $element = grasmash_process_ajax_import($element);
 
    return $element;
  }
 
}
 
/**
 * Recursively removes profile2 field prefixes from each array row.
 * This ensures that all input names on the destination form are correct.
 */
function grasmash_process_ajax_import($element){
  foreach ($element as $key => $value){
    if (is_string($element[$key]) && !is_numeric($element[$key])){
      $element[$key] = preg_replace('@(profile_seeker_profile){1}(\[){1}([^\]]+){1}(\]){1}@','$3$5', $element[$key]);
      $element[$key] = str_replace('profile-seeker-profile-','', $element[$key]);
      $element[$key] = str_replace('profile_seeker_profile_','', $element[$key]);
      if ($element[$key] == 'profile_seeker_profile') {
        unset($element[$key]);
      }
    }
    elseif (is_array($element[$key])){
      $element[$key] = grasmash_process_ajax_import($element[$key]);
    }
  }
  return $element;
}

Drupal Version Compatibility:

Comments

Thanks for sharing!

Maybe you could achieve the same result with field_attach_form and filter out those that you don't need.

Pedro, I think that field_attach_form would work. Deciding to use it would probably depend on how many fields you'd like to import at once, and how closely the source and target forms match.

I haven't used field_attach_form yet, what happens when you attach a form from a source that contains fields which aren't present in the target? Do they get added or ignored?

Add new comment

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.