I'm building a custom form for one of my content types. I want to be able to import some of the existing fields and save out the node programmatically.

On drupal 7 I always used the field_attach_form function to do this for me. It looks like that function has been removed in Drupal 8. Can anyone give me some pointers on how I can do the same thing and include fields from a content type in my custom form?

I've scoured the internet looking for this all day, any help would be appreciated.

Thanks

Comments

Ismail Cherri’s picture

You could use the following code:

<?php
//Create an empty representative entity
$node = \Drupal::service('entity_type.manager')->getStorage('node')->create(array(
                'type' => 'article'
            )
        );

//Get the EntityFormDisplay (i.e. the default Form Display) of this content type
$entity_form_display = \Drupal::service('entity_type.manager')->getStorage('entity_form_display')
                                        ->load('node.article.default');

//Get the body field widget and add it to the form
if ($widget = $entity_form_display->getRenderer('body')) { //Returns the widget class
  $items = $entity->get('body''); //Returns the FieldItemsList interface
  $items->filterEmptyItems();
  $form['body'] = $widget->form($items, $form, $form_state); //Builds the widget form and attach it to your form
  $form['body']['#access'] = $items->access('edit');
}
webdevfreak’s picture

This code works for me in Drupal 9 apart from following i.e 

a) Variable $node on line 2 should be replaced with $entity as called here

$items = $entity->get('body''); //Returns the FieldItemsList interface

b) Add this line at the end otherwise it throws strange error i.e 

$form['#parents'] = [];

c) Also we can render most of our content type fields by using foreach loop e.g 

// Content type field array.
$field_array = [
'title',
'field_registered_address',
'field_billing_address',
'field_shipping_address',
];

 

// Loop
foreach ($entity_form_display->getComponents() as $name => $component) {
if(in_array($name, $field_array)){
$widget = $entity_form_display->getRenderer($name);

if (!$widget) {
continue;
}

$items = $entity->get($name);
$items->filterEmptyItems();
$form[$name] = $widget->form($items, $form, $form_state);
$form[$name]['#access'] = $items->access('edit');
}

$form['#parents'] = [];
}

bojanz’s picture

You use the form display object for that.

  $form_display = EntityFormDisplay::collectRenderDisplay($entity, $form_mode);
  $form_display->buildForm($entity, $entity_form, $form_state);

See EntityInlineForm in inline_entity_form for an example that has validation and submission as well.