2

When displaying my entity edit form with \Drupal::formBuilder()->getForm($form); (for a flagging attached to a node) in a View that is set to show Content with the Default display, I noticed the <form> tag itself is missing:

<form class="flagging-myflag-edit-form flagging-form" data-drupal-selector="flagging-myflag-edit-form-iq8dn9lwifq" action="/flag/details/edit/MYFLAG/52" method="post" id="myform-myflag-edit-form--iq8dn9lWIfQ" accept-charset="UTF-8">
Everything between the form tags is printed properly.
</form>

The <form> tag appears on the node page correctly, but it does not appear in the view.

So somehow, Views is filtering out the <form> tag, but I need to keep this tag.

This is the code I am using:

function MYMODULE_node_view(array &$build, NodeInterface $node, EntityViewDisplayInterface $display, $view_mode) {
  if ($node->getType() == 'MY_CONTENT_YTPE') {
    if ($display->getComponent('my_flagging_form')) {
      $flag = \Drupal::service('flag')->getFlagById('MY_FLAG');
      $flagging_entity = \Drupal::service('flag')->getFlagging($flag, $node);
      $form = \Drupal::service('entity.manager')
        ->getFormObject('flagging', 'edit')
        ->setEntity($flagging_entity);
      $build['my_flagging_form'] = \Drupal::formBuilder()->getForm($form);
    }
  }
}

According to twig debugging, the custom form is being output through core/modules/system/templates/form.html.twig, but there's no form tag when output by Views (the tag does appear on the node page).

This is form.html.twig:

<form{{ attributes }}>
  {{ children }}
</form>

EDIT: I tried to render it based on the comment of @Ales:

  $form = \Drupal::service('entity.manager')
    ->getFormObject('flagging', 'edit')
    ->setEntity($flagging_entity);
  $form_to_render = \Drupal::formBuilder()->getForm($form);
  $renderer = \Drupal::service('renderer');
  $build['remember_form']['#markup'] = $renderer->render($form_to_render);

This gives me the same output as my original code; the form is there, but the <form> tag is not...

EDIT 2: I also tried using template_node_preprocess() instead of hook_node_view():

function MYTHEME_preprocess_node__MY_CONTENT_TYPE(&$variables) {
  $node = $variables['node'];
  $flag = \Drupal::service('flag')->getFlagById('MY_FLAG');
  $flagging_entity = \Drupal::service('flag')->getFlagging($flag, $node);
  $form = \Drupal::service('entity.manager')
    ->getFormObject('flagging', 'edit')
    ->setEntity($flagging_entity);
  $form_to_render = \Drupal::formBuilder()->getForm($form);
  $variables['MY_FLAG_form'] = $form_to_render;
}

But when I rendered this variable in my theme template, I got the same result-- the <form> tag appears on the node page, but not in the view that shows Content with mode full content.

8
  • 1
    hello, you have to render it $renderer = \Drupal::service('renderer'); $myFormHtml = $renderer->render($ \Drupal::formBuilder()->getForm($form););
    – Ales
    Jul 10 '20 at 14:59
  • @Ales Thanks for the suggestion, but I just tried that and I didn't get a <form> tag that way, either. See my updated question. Jul 10 '20 at 16:38
  • 1
    Hm ok. Thanks for letting me know. I came across with another idea. Use render element form drupal.stackexchange.com/a/264114/83224
    – Ales
    Jul 11 '20 at 6:25
  • 1
    I am not exactly sure what the problem could be - I have passed a renderable form array as a variable to node templates a lot and have never ran into this. The one thing I would change personally is using preprocess_node instead of hook_node_view, and in the node template rendering the form array with {{ myform }}
    – Kevin
    Jul 12 '20 at 13:45
  • 2
    could it be that you are rendering this form inside another form? like views exposed filter template
    – milkovsky
    Jul 13 '20 at 7:33
1
+100

Looks like views reformats rendering as a form if there are any form elements in a row. See \Drupal\views\Plugin\views\display\DisplayPluginBase::elementPreRender:

    // If form fields were found in the view, reformat the view output as a form.
    if ($view->hasFormElements()) {
      .....
    }

I guess you should see one <form> tag arround the entire view.

In this case a possible solution would be to create a custom views display plugin Forms, that overrides the elementPreRender method and ignores the form elements check.

3
  • Tip: rendering one form per row might generate a lot of entries in the forms cache table. I would suggest to consider using an ajax link instead for flagging.
    – milkovsky
    Jul 13 '20 at 8:14
  • I need to edit the flagging fields on the node page, which is why I'm embedding the form. Is there a way to disable the caching for this specific form? Jul 13 '20 at 10:34
  • 1
    @PatrickKenny I guess $form['#cache'] = ['max-age' => 0]; should work in fom_alter. Bu please double check the problem with the foem caching. It might be fine. I did something similar long time ago with drupal 7.
    – milkovsky
    Jul 13 '20 at 12:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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