3

I want to add a link field to my custom form.
Below is the code that I have been trying to use but no success. So can anyone let me know how to use core link field in a custom form in Drupal8?
The below code works for Drupal7 but not for Drupal8. I have also tried using #type => 'link' in the below code.

$form['cta'] = [
  '#type' => 'link_field',
  '#field_name' => 'link_field',
  '#field_parents' => array(),
  '#delta' => 0,  
];
return $form;

5 Answers 5

1

To make: Custom Custom url field behave similar like as core link widget's url field(that add from backend) : then can add additional attributes: 'element_validate', 'attributes' etc

Code:

$form['resource_fieldset']['design_tool_link'] = [
  '#type' => 'entity_autocomplete',
  '#target_type' => 'node',
  '#title' => $this->t('Design Tool Link'),
  '#description' => $this->t('Select Design Tool Link'),
  '#required' => TRUE,
  '#element_validate' => [
    [
      'Drupal\link\Plugin\Field\FieldWidget\LinkWidget',
      'validateUriElement',
    ],
  ],
  '#attributes' => [
    'data-autocomplete-first-character-blacklist' => '/#?',
  ],
  '#process_default_value' => FALSE,
  '#default_value' => $design_tool_link ?? : '',
];

Note: by adding #element_validate attribute :

  • Custom Url field 'll accept external & internal links as default core link widget's URL field do
  • Also validation of core link 'll applied instead of writing same validation again
0

I think you have to create two seperate form fields to do this in Drupal 8.

You can use textfield for the title and url for the URL field, like this:

$form['cta_title'] = [
  '#type' => 'textfield',
  '#title' => t('CTA Title'),
];

$form['cta_url'] = [
  '#type' => 'url',
  '#title' => t('CTA Url'),
];

return $form;

Another solution is to pull the widget out from an entity display. There is a guide how to do that here, https://www.webomelette.com/how-render-entity-field-widgets-inside-custom-form-drupal-8.

Basically you load the entity display,

$entity = $this->entityTypeManager->getStorage('node')->create(['type' => 'article']);
$form_display = $this->entityTypeManager->getStorage('entity_form_display')->load('node.article.custom_form_display');

And then you pull out the widgets and add them to your form,

foreach ($form_display->getComponents() as $name => $component) {
  $widget = $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');
}
1
  • 2
    I am aware of this possibility. At last I will go with this only if I did not get to make that work.However I want to know if there is any way so that we can use the core link field widget in a custom form that gives us the same widget as we get when we create a link field in a content type created through admin UI. Dec 9, 2019 at 10:15
0

Thanks for the comments, both of you have actually redirected me in the right direction. Below are the actual steps that I took to achieve this:

  • Create a link field (field_url) in one of the content types using admin UI. and use the below code to use that field widget in your custom form or custom block.

    $form['#parents'] = [];
    // Create an empty representative entity.
    $node = \Drupal::service('entity_type.manager')->getStorage('node')->create([
      'type' => 'upcoming_webinar',
    ]
    );
    // 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.upcoming_webinar.default');
    // Get the body field widget and add it to the form.
    // Returns the widget class.
    if ($widget = $entity_form_display->getRenderer('field_url')) {
      // Returns the FieldItemsList interface.
      $items = $node->get('field_url');
      $items->filterEmptyItems();
      // Builds the widget form and attach it to your form.
      $form['field_url'] = $widget->form($items, $form, $form_state);
      $form['field_url']['#access'] = $items->access('edit');
    }
    
1
  • 1
    Hmm, as far as I see this is pretty much the same answer as mine.
    – user72672
    Dec 9, 2019 at 15:09
0

If you have a link field attached to any entity like a node bundle, or user or ... then you can use a code like this:

// Create an empty representative entity.
$node = \Drupal::service('entity_type.manager')
  ->getStorage('node')->create(['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 = $node->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');
}
0

Core's link field actually uses a '#type' => 'url' form element as base and if the field is configured to support internal links it switches to '#type' => 'entity_autocomplete'. See /core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php L186-203

So if you just want to be able to select entities go for '#type' => 'entity_autocomplete'.

$form['cta'] = [
  '#type' => 'entity_autocomplete',
  '#target_type' => 'node',
];

And if you want to be able to type external URLs there as well you need to override the element validation yourself. Nonetheless you need to add your own simple '#type' => 'textfield' element to pick up a user entered title. Same as the link widget does it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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