10

I have a very complex situation where I need some advice. I have a content type my_content, which has a field collection field attached to it field_mycollection, which has an entity reference field referencing to user field_my_userreference, a phone field field_my_phone, a text field field_my_text, and another text field field_my_anothertext.

My Content
|_ field_mycollection
   |_ field_my_userreference
   |_ field_my_phone
   |_ field_my_text
   |_ field_my_anothertext

The user entity has also have fields field_my_phone, field_my_text and field_my_yetanothertext which the latter has a different machine name.

What I want to do, if in my_content edit/add form, in field_my_userreference a user is selected, the other fields should be auto-populated from the selected user's data. The auto-populated fields should still be editable.

How could I achieve this goal? I'd like to do it, if possible, with some coding, using hook_form_FORM_ID_alter().

  • Do you need it to happen live on form, or on save? – Mołot Aug 28 '13 at 12:18
  • Live on form. I have already implemented it that on save, that the data will taken from user entity if left empty. But actually what I need it on form :( – Елин Й. Aug 28 '13 at 12:26
  • OK, posed my answer. – Mołot Aug 28 '13 at 12:34
11

If you want it to happen live, and all fields are on the form already, safest way would be to use hook_form_FORM_ID_alter() to add following to a form:

$form['#attached']['js'] = array(
  drupal_get_path('module', 'module_name') . '/js/copy_field_value.js',
);

Then in copy_field_value.js create behavior:

(function($) {
  Drupal.behaviors.moduleNameCopyFieldValue = {
    attach: function (context, settings) {

      // Repeat this for all fields as needed
      $('#source', context).on('blur', function () { 
        // above you can use change instead of blur if element is not changed by another js
        if (!$('#destination').val() || 0 === $('#destination').val().length) {
          $('#destination').val($(this).val());
          // wrap line above in "if no value" like I did, or other condition you like
        }
      });
      // end of "repeat this"
    }
  };
})(jQuery);

You can also use hook_form_FORM_ID_alter() to add #ajax parameter to source field, but it would make your form to call a server on each field copy. If you need to actually query database, it is the way to go. It would be pretty broad to describe it anew here. You need to alter $form_state["input"] array to update real values seen by user. Do it in form creation function, wrapping it with isset to avoid notices.

If your form element is $form["something"]["something"]["element"], its value will be in $form_state["input"]["something"]["something"]["element"] - and you can set it in hook_form_alter all right, just remember to take both $form and $form_state by reference.

Note: .on() method was added in jQuery 1.7, so you will need jQuery Update to use this answer directly, or translate my code to use .change() or .blur() method.

  • Many thanks for the instructions! I am not very well on Drupal's JS API. Would you explain how I get the field values from user entity? For example, if a user is selected, how can I populate the next fields with this user's info? – Елин Й. Aug 28 '13 at 12:34
  • 1
    @ЕлинЙ. the trick here is not to care about php background. Just identify ID parameters of <input> tags using Firebug or similar tool for your favourite browser. Or use any other jQuery selector. It will happen in browser only, so you have what you have on screen. On the other hand if you need to actually query database (seems I missed that), #ajax is the way to go. But it would be pretty broad. You need to alter $form_state["values"] array to update real values seen by user. Do it in form creation function, wrapping it with isset to avoid notices. – Mołot Aug 28 '13 at 12:39
  • Thanks again @Mołot, I'll try to implement it tomorrow, or maybe this evening. It seems I will need a few hours to get it really work, if not more. – Елин Й. Aug 28 '13 at 12:49
  • @ЕлинЙ. good luck, feel free to return with more questions and link them here in comments if they are connected. Updated answer a bit, btw. – Mołot Aug 28 '13 at 12:56
  • 1
    Ok, I'll experiment it a bit and I'll write my experiences. – Елин Й. Aug 28 '13 at 13:05
4

You can do it using the computed field module

Computed Field is a very powerful CCK field module that lets you add a custom "computed fields" to your content types. These computed fields are populated with values that you define via PHP code. You may draw on anything available to Drupal, including other fields, the current user, database tables, you name it. (Feeling the power yet? :) ) You can also choose whether to store your computed field values in the database with other content fields, or have them "calculated" on the fly during node views. (Although you should note that Views use requires database stored values.) This field is literally the Swiss Army knife of CCK fields. So start cooking up your PHP based values!

  • Thanks for the quick response. It sounds very promising. Though, I don't want to install a module for that but simply write some code, since I need such a functionality only on that form, and the actual system is already too big and many modules are installed for diverse functionalities. – Елин Й. Aug 28 '13 at 12:23
  • Secondly, is it possible using this module, for the user who is creating or editing the node to override the auto-populated fields manually and save? So that, in the user entity and my_content are different values are saved. – Елин Й. Aug 28 '13 at 12:24
  • That would depend on the way it is setup – 4life Aug 28 '13 at 12:40
  • Thanks @4life, I'll give that also a try if I can't achieve it with coding, using the instructions of Mołot. – Елин Й. Aug 28 '13 at 12:51
2

I want to post how I achieved it thanks to great helps of @Mołot.

  1. Implemented the hook_form_FORM_ID_alter().
  2. Added a wrapping div around the field collection.
  3. Since the my field collection is a multi-value field, iterated over it and set the #ajax property for the field field_my_userreference.
  4. Created a callback function which simply returns the field collection item back.
  5. Checked in the hook_form_FORM_ID_alter() implementation, if $form_state for the field collection is set. If yes, get the values from the user entity and populate the form input fields with those values.

My code looks like:

function MYMODULE_form_my_content_node_form_alter(&$form, &$form_state, $form_id) {
  $form['field_mycollection']['#prefix'] = '<div id="mycollection-wrapper">';
  $form['field_mycollection']['#suffix'] = '</div>';
  foreach ($form['field_mycollection']['und'] as $key => $fc_mycollection) {
    if (is_numeric($key)) {
      $form['field_mycollection']['und'][$key]['field_my_userreference']['und']['#ajax'] = array(
        'callback' => 'MYMODULE_mycollection_callback',
        'wrapper' => 'mycollection-wrapper',
      );
      if (isset($form_state['values']['field_mycollection']['und'][$key]['field_my_userreference']['und'][0]['target_id'])) {
        $user_wrapper = entity_metadata_wrapper('user', $form_state['values']['field_mycollection']['und'][$key]['field_my_userreference']['und'][0]['target_id']);
        $form_state['input']['field_mycollection']['und'][$key]['field_my_text']['und'][0]['value'] = $user_wrapper->field_my_text->value() ? $user_wrapper->field_my_text->value() : '';
        $form_state['input']['field_mycollection']['und'][$key]['field_my_anothertext']['und'][0]['value'] = $user_wrapper->field_my_text->value() ? $user_wrapper->field_my_yetanothertext->value() : '';
      }
    }
  }
}

function MYMODULE_mycollection_callback($form, &$form_state) {
  return $form['field_mycollection'];
}
0

This might be a little late but this module https://www.drupal.org/project/entityreference_autofill, seems to do what you are describing. I have used it and it can help you as well.

Not the answer you're looking for? Browse other questions tagged or ask your own question.