Hello world,

I was wondering how to prepopulate an entity form from hook_from_alter().

In my case, I have a bunch of stories and another content type "Press folder" that references these stories.
When I create a new "Press folder" content, I would like the reference to be pre-populated with 2 random stories.

I can access the field through the hook but I REALLY don't know what to put into.
I tried to overwrite the field using the function inline_entity_form_field_widget_form() but without success.

Any help would be appreciated...
Thanks for your time. ;)

CommentFileSizeAuthor
#15 NewBox.png61.59 KBmenteora

Comments

bojanz’s picture

Status: Active » Fixed

Use hook_inline_entity_form_entity_form_alter().
You have an example in inline_entity_form.api.php

m42’s picture

Status: Fixed » Active

Thx bojan for your answer, but it seems I've explained myself badly.

1. I have a main content type called "Press release" that contains an EntityReference field called "Referenced stories"
2. This field ("Referenced stories") references contents of type "Story"

When I create a new content of type "Press release" (which is empty at startup), I would like to have its field "Referenced stories" already filled with 2 stories.

I tried to use hook_inline_entity_form_entity_form_alter() as you mentioned but it isn't even triggered...
Following your comments, it only triggers when a node form is called, so when I MANUALLY try to create or to edit a node reference.

But what I would like to do is to pre-populate this field at startup with existing nodes.

Do you see what I mean (my English is broken, I know... :p) and how to do it ?

m42’s picture

Status: Active » Fixed

After days of analysis and reflexion, I'm now able to answer myself. Hoping this can help anyone in the future.

The following piece of code worked in my case (I removed the "Delete" button as I didn't want users to be able to) :

function mymodule_field_widget_form_alter(&$element, &$form_state, $context) {
    if (isset($element['#field_name']) && 'YOUR-FIELD-NAME' == $element['#field_name']) {
       // Do it only where no default value is set
       if (!isset($element['entities'][0])) {
            $delta = 0;
            $cloneList = array(...); // Put here nids you want to prepopulate with
            
            // In the "invisible" form, find out the part that really helps us here
            foreach($form_state['inline_entity_form'] as $keyState => $formStateItem){
                if('CONTENT-TYPE-SET-IN-FIELD-DEFINITION' == $formStateItem['settings']['bundles'][0]){
                    break;
                }
            }
            
            // Modify the visible part
            $entityList = entity_load('node', $cloneList);
            foreach ($entityList as $key => $entity) {
                // The whole list can be found in inline_entity_form.module, around line 350
                $element['entities'][$delta] = array();
                $element['entities'][$delta]['#entity'] = $entity;
                $element['entities'][$delta]['#needs_save'] = FALSE;
                $element['entities'][$delta]['#weight'] = 0;
                $element['entities'][$delta]['delta'] = array(
                    '#type' => 'weight',
                    '#default_value' => $delta,
                    '#attributes' => array('class' => array(0 => ' ief-entity-delta'))
                );
                $element['entities'][$delta]['actions'] = array(
                    '#type' => 'container',
                    '#attributes' => array('class' => array(0 => ' ief-entity-operations')),
                    'ief_entity_edit' => array(
                        '#type' => 'submit',
                        '#value' => t('Edit'),
                        '#name' => 'ief-' . $keyState . '-entity-edit-' . $delta ,
                        '#limit_validation_errors' => array(),
                        '#ajax' => array(
                            'callback' => 'inline_entity_form_get_element',
                            'wrapper' => 'inline-entity-form-'.$keyState,
                        ),
                        '#submit' => array('inline_entity_form_open_row_form'),
                        '#ief_row_delta' => $delta,
                        '#ief_row_form' => 'edit',
                    )
                );

                // Modifiy the invisible part
                $form_state['inline_entity_form'][$keyState]['entities'][$delta] = array(
                    'entity' => $entity,
                    'weight' => 0,
                    'form' => NULL,
                    'needs_save' => FALSE
                );
       }
    }
}

Status: Fixed » Closed (fixed)

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

apassi’s picture

Hi,

Nice job, any ideas how to prepopulate n-pieces new entities? Like ief single widget, but for multiple nodes.

Makku01’s picture

Issue summary: View changes

@hbemtec - you, sir, saved my day!

To prepopulate new entities you can do:

$newEntity = entity_create('node', array('type' =>'YOURNODETYPE'));
$newEntity->uid = $user->uid;
$newEntity->{$field_name} = 'something';

and paste $newEntity where hbemtec put $entity. Do not forget to change the 'needs_save' values to TRUE.

a.milkovsky’s picture

@hbemtec, @Makku01 thanks a lot for sharing this!

If you want to have the forms expanded by default you can use next code:

(I used a bit different variable names comparing to the initial hbemtec's example, but you will get the idea)


// ... Other code ...

$settings = inline_entity_form_settings($context['field'], $context['instance']);
$bundle = reset($settings['create_bundles']);
$controller = inline_entity_form_get_controller($context['instance']);
$parents = array_merge($element['#field_parents'], array($element['#field_name'], $element['#language']));
$parent_langcode = entity_language($element['#entity_type'], $element['#entity']);

// Modify the visible part.
$entityList = entity_load('node', $cloneList);
foreach ($entityList as $key => $entity) {

// ... Other code ... Do not forget to remove $element['entities'][$delta]['actions'] here.

  $element['entities'][$delta]['delta'] = array(
    '#type' => 'value',
    '#value' => $delta,
  );
  // Add the appropriate form.
  $element['entities'][$delta]['form'] = array(
    '#type' => 'container',
    '#attributes' => array('class' => array('ief-form', 'ief-form-row')),
    '#op' => 'edit',
    '#parents' => array_merge($parents, array('entities', $delta, 'form')),
    '#entity' => $entity,
    '#entity_type' => $settings['entity_type'],
    '#parent_language' => $parent_langcode,
    '#ief_id' => $ief_id,
    '#ief_row_delta' => $delta,
  );
  $element['entities'][$delta]['form'] += inline_entity_form_entity_form($controller, $element['entities'][$delta]['form'], $form_state);
  
  // Modify form state to open ief.
  $form_state['inline_entity_form'][$ief_id]['entities'][$delta] = array(
    'entity' => $entity,
    'weight' => 0,
    'form' => 'add',
    'form settings' => array(
      'bundle' => $bundle,
    ),
    'needs_save' => FALSE,
  );
}

In general just follow inline_entity_form_field_widget_form() for additional cases.

strings6’s picture

I found this post very helpful! I modified the code slightly to work on three different fields, and pull the $cloneList nids from values stored in a user's profile. Cool stuff!

However... I also added back the delete button because I want the user to be able to remove the preset value and change to something else if they want. But the code just forces it right back to the preset value even after I remove it.

Does anyone know what value I can check against to make sure it only sets a preset initially, but let's it go if I remove the preset reference?

Thanks!

strings6’s picture

I figured out "a way" but who knows if it's a "good way".

After the logic occurs, I do:

$form_state['default_'.$element['#field_name'].'_already_set'] = TRUE;

And then I wrapped the entire logic in an if statement to check that the value isn't set before executing. LOL... I doubt adding another arm to $form_state is a great idea, but it works for now.

I also added a check to make sure arg(1) == "add" so it doesn't happen on an edit operation. Otherwise, after you delete an existing value, it wants to flip to the default value instantly (which would be weird).

vaene’s picture

Hey here is how I pulled it all together. I created a Card Content Type with an Entity Reference, Title, Blurb(body) and Image; plus a couple of other fields. The idea is that the Card would be a wrapper for the Article and the Editor could change the Title, Blurb and Image and still have it link to the Node Referenced in the Entity Reference Field. I then set up the Newsletter so it would pull in 10 Blank Cards and open the forms up so the editors could quickly go down and fill in the content. Peachy. Except now I am trying to get the Title Blurb and Image fields to prepopulate with the Node info from their respective Entity Reference when an article is selected there. Having trouble with the Ajax part of it so if anyone has any suggestions, I'd love to hear them!

Drupal Ajax fun.


    /**
     * @file
     * MYMODULE_card.ajax.inc
     */

    /**
     * Implements hook_form_FORM_ID_alter().
     */
    function MYMODULE_card_form_card_node_form_alter(&$form, &$form_state, $form_id) {

      $form['field_content'][LANGUAGE_NONE][0]['target_id']['#ajax'] = array(
          'callback' => 'MYMODULE_card_overrides',
          'event' => 'autocompleteSelect',
          'wrapper' => 'card_form',
        );
      // Wrap the title field
       $form['#prefix'] = '<div id="card_form">';
       $form['#suffix'] = '</div>';

      if (!empty($form_state['values']['field_content'][LANGUAGE_NONE][0]['target_id'])) {
        // Load the node from target_id.
        unset($form_state['input']['title']);
        unset($form_state['input']['field_blurb_override']);
        unset($form_state['input']['field_image_override']);
        unset($form_state['input']['field_link_override']);

    $target_node = node_load($form_state['values']['field_content'][LANGUAGE_NONE][0]['target_id']);
    $form['title']['#default_value'] = $target_node->title;

    // Set Blurb.
        $blurb = '';
        if (!empty($target_node->body[LANGUAGE_NONE][0]['summary'])){
          $blurb = $target_node->body[LANGUAGE_NONE][0]['summary'];
        }
        $form['field_blurb_override'][LANGUAGE_NONE][0]['#default_value'] = $blurb;

        // Set image.
        $form['field_image_override'][LANGUAGE_NONE][0]['#default_value']['fid'] = $target_node->field_image_homepage_story[LANGUAGE_NONE][0]['fid'];

        // Set link.
        // TODO: use url() with ABSOLUTE once we get that working again.
        $link_value = 'http://MYSITE.com/' . drupal_get_path_alias('node/' . $target_node->nid);

        $form['field_link_override'][LANGUAGE_NONE][0]['#default_value']['url'] = $link_value;
      }
    

      dpm($form,'form card');
      dpm($form_state,'form_state card');
      return $form;
    }

    function MYMODULE_card_overrides(&$form, $form_state) {

      return $form;
    }

This works great on its own, but in the IEF fails cause, hey different form. So I am trying to get the ajax to work when Card is used as an IEF in the Newsletter CT. The code below uses what I found above to make 10 IEFs and open them up for editing. I also use it to put in an AJAX callback per IEF. But now am stuck on what to modify in the form_state and what to return from the form in MYMODULE_newsletter_overrides to get it to work like the card does on its own. As you can see I have even tried ajax_command_invoke to get this working as well, but no dice. Any pointers would be greatly appreciated!

This part brings in 10 ief forms based on the Card CT and opens them up per the suggestions in previous posts.


 
    function MYMODULE_newsletter_field_widget_form_alter(&$element, &$form_state, $context) {
      global $user;

      if (isset($element['#field_name']) && 'field_article_card' == $element['#field_name']) {

        ////dpm($element, 'element');
        //dpm($form_state, 'form_state');
        //dpm($context, 'context');
        // Do it only where no default value is set
        $entityList = array();
        if (!isset($element['entities'][0])) {
          $delta = 0;
          // Starting with new set of empty cards
          //$cloneList = array(...); // Put here nids you want to prepopulate with

          for ($i = 0; $i < 10; $i++) {
            $newEntity = entity_create('node', array('type' => 'card'));
            $newEntity->uid = $user->uid;
            $newEntity->title = 'Article Card ' . $i;
            $entityList[$i] = $newEntity;
          }
        }
        // In the "invisible" form, find out the part that really helps us here
        foreach ($form_state['inline_entity_form'] as $keyState => $formStateItem) {
          if ('card' == $formStateItem['settings']['bundles'][0]) {
            break;
          }
        }

        // Setup bundle for auto open each form
        $settings = inline_entity_form_settings($context['field'], $context['instance']);
        $bundle = reset($settings['create_bundles']);
        $controller = inline_entity_form_get_controller($context['instance']);
        $parents = array_merge($element['#field_parents'], array($element['#field_name'], $element['#language']));
        $parent_langcode = entity_language($element['#entity_type'], $element['#entity']);


        // Modify the visible part

        //dpm($entityList, 'entityList');
        //$entityList = entity_load('node', $cloneList);
        foreach ($entityList as $delta => $entity) {
          // The whole list can be found in inline_entity_form.module, around line 350

          $element['entities'][$delta] = array();
          $element['entities'][$delta]['#entity'] = $entity;
          $element['entities'][$delta]['#needs_save'] = TRUE;
          $element['entities'][$delta]['#weight'] = 0;

          $element['entities'][$delta]['delta'] = array(
            '#type' => 'value',
            '#value' => $delta,
          );
          // Add the appropriate form.
          $element['entities'][$delta]['form'] = array(
            '#type' => 'container',
            '#attributes' => array('class' => array('ief-form', 'ief-form-row')),
            '#op' => 'edit',
            '#parents' => array_merge($parents, array('entities', $delta, 'form')),
            '#entity' => $entity,
            '#entity_type' => $settings['entity_type'],
            '#parent_language' => $parent_langcode,
            '#ief_id' => $keyState,
            '#ief_row_delta' => $delta,
          );
          $element['entities'][$delta]['form'] += inline_entity_form_entity_form($controller, $element['entities'][$delta]['form'], $form_state);

          $form_state['inline_entity_form'][$keyState]['entities'][$delta] = array(
            'entity' => $entity,
            'weight' => 0,
            'form' => 'add',
            'form settings' => array(
              'bundle' => $bundle,
            ),
            'needs_save' => FALSE,
          );

          // Add ajax form autocomplete to each ief
          $card_form_id = 'card_form_' . $delta;
          $element['entities'][$delta]['form']['field_content'][LANGUAGE_NONE][0]['target_id']['#ajax'] = array(
            'callback' => 'MYMODULE_newsletter_overrides',
            'event' => 'autocompleteSelect',
            'wrapper' => $card_form_id,
          );
          // Wrap the ief
          $element['entities'][$delta]['form']['#prefix'] = '<div id="' . $card_form_id . '">';
          $element['entities'][$delta]['form']['#suffix'] = '</div>';

          //dpm($form_state['inline_entity_form'][$keyState], 'form state entities');
          //dpm($element,'element');
        }
      }
    }

    function MYMODULE_newsletter_overrides(&$form, $form_state) {
      //dpm($form_state, 'formstate overrides');
      //dpm($form, 'form overrides');

      $triggering_element = $form_state['triggering_element'];
      $triggering_field_name = $triggering_element['#field_name'];
      $parent = $triggering_element['#parents'][0];
      $parent_id = $triggering_element['#parents'][3];

      $target_node = node_load($triggering_element['#entity']->field_content[LANGUAGE_NONE][0]['target_id']);

      // Assign fields to address.
      $title_field = 'input[name="' . $parent . '[' . LANGUAGE_NONE . '][entities][' . $parent_id . '][form][title][' . LANGUAGE_NONE . '][0][value]"]';
      $blurb_field = 'textarea[name="' . $parent . '[' . LANGUAGE_NONE . '][entities][' . $parent_id . '][form][field_blurb_override][' . LANGUAGE_NONE . '][0][value]"]';
      $image_field = 'input[name="' . $parent . '[' . LANGUAGE_NONE . '][entities][' . $parent_id . '][form][field_image_override][' . LANGUAGE_NONE . '][0][fid]"]';

      // Get values from target node.
      $promo_title = $target_node->field_promo_title[LANGUAGE_NONE][0]['value'];
      $card_title = empty($promo_title) ? $target_node->title : $promo_title;
      $card_blurb = $target_node->body[LANGUAGE_NONE][0]['summary'];
      $card_image_fid = $target_node->field_image_homepage_story[LANGUAGE_NONE][0]['fid'];

      $commands[] = ajax_command_invoke($title_field, 'val', array($card_title));
      $commands[] = ajax_command_invoke($blurb_field, 'val', array($card_blurb));
      $commands[] = ajax_command_invoke($image_field, 'val', array($card_image_fid));

      $path = libraries_get_path('FirePHPCore');
      if (file_exists($path . '/fb.php')) {
        include_once $path . '/fb.php';
        include_once $path . '/FirePHP.class.php';

        dfb($form_state, 'MYMODULE_newsletter_overrides: $form_state', FirePHP::WARN);
        dfb($form, 'MYMODULE_newsletter_overrides: $form', FirePHP::WARN);
        dfb($form_state['triggering_element'],'MYMODULE_newsletter_overrides: $form_state triggering_element', FirePHP::WARN);
        dfb($triggering_element['#entity']->field_content[LANGUAGE_NONE][0]['target_id'],'MYMODULE_newsletter_overrides: target_id', FirePHP::WARN);
      }
      

    //  return array(
    //    '#type' => 'ajax',
    //    '#commands' => $commands,
    //  );
      return $form['field_article_card'][LANGUAGE_NONE]['entities'][$parent_id];

    }
vyasamit2007’s picture

Version: 7.x-1.x-dev » 8.x-1.x-dev

How do you do this in D8?

mikran’s picture

(this post is about d7)

I didn't want to accept a solution that is essentially rewriting a large part of the widget form. So I did some digging, and I found out a simpler way to prepopulate values to any field. There is no UI for this but fields can be configured to use default_value_function.

So I updated my IEF field:

$instances = field_info_instances('node', 'article');
$instances['my_ief_field']['default_value_function'] = 'my_module_default_value_function';
field_update_instance($instances['my_ief_field']);

and after running that you should update the feature containing said field if using features.

Then adding a default value is as easy as:

function my_module_default_value_function($entity_type, $entity, $field, $instance, $langcode) {
  return array(array('target_id' => 123));
}
pianomansam’s picture

Version: 8.x-1.x-dev » 7.x-1.x-dev

Switching back to D7 so we can start a new issue for D8.

menteora’s picture

@mikran your solution is great for me!

Is possible append to array (inside 'my_module_default_value_function') a new entity (without target_id)?

I want to save this last new created entity on node 'article' save event.

Thank you very mutch!

menteora’s picture

StatusFileSize
new61.59 KB

I think I must apply solution #3 (thank you @hbemtec) to create new entity reference.

How can I disable new box opens automatically?

(sorry for my english, I attach one picture to clarify my question)

dbiscalchin’s picture

Hi everyone,

Thanks everybody for all these examples. They helped me a lot to get things working.
However, I agree with @mikran and I don't think a solution that basically rewrites a large piece of a third-party code is good enough. Yet I haven't found a better solution to prepopulate with new entities.
My suggestion is to create a hook allowing other modules to provide the entities to be prepopulated by inline_entity_form_field_widget_form() instead. This hook could be called just after the entities are loaded and added to $form_state (around line 478 of inline_entity_form.module in 7.x branch).

Regards,