Drupal - How do I embed a form in a controller response?

To embed a form in a renderable array, you use:

$form_class = '\Drupal\my_module\Form\MyForm';
$build['form'] = \Drupal::formBuilder()->getForm($form_class);

Which is similar to your code.

But the problem is of a different nature. You are extending a special controller, one that returns a renderable array of '#type' => 'page'. It uses the page template to render the output and that template does not contain the {{ layout_control }} variable to output your form. If you use $page['header']['layout_control'] = ... to add the form to the render array, it should show the form in the header region of the layout demo page.


You can render a form and place it wherever you want in your markup.

In your controller method, you want to do $this->formBuilder()->getForm() and then render that form array using \Drupal::service('renderer')->render()

I'm not sure what side effects this might have with submission / error control if you have multiple forms on a single page but it is possible to do it.

See below controller

<?php

namespace Drupal\my_module\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Render\Markup;

class MyController extends ControllerBase
{

    public function displayForm()
    {

        $myForm = $this->formBuilder()->getForm('Drupal\my_module\Form\MyForm');
        $renderer = \Drupal::service('renderer');
        $myFormHtml = $renderer->render($myForm);

        return [
            '#markup' => Markup::create("
                <h2>My Form is Below</h2>
                {$myFormHtml}
                <h2>My Form is Above</h2>
            ")
        ];
    }
}

So it turns out that Drupal 8 doesn't let you to do the kind of loose, willy-nilly page alteration that Drupal 7 allowed. Instead, you have to use one of the hooks which replace hook_page_build() and hook_page_alter(). In particular, hook_page_top() and hook_page_bottom() are where you can insert arbitrary renderable elements.

There's an API change record explaining this: https://www.drupal.org/node/2357755.

Here's the code I used to fix my problem (in the .module file):

/**
 * Implements hook_page_bottom().
 */
function block_ui_page_bottom(array &$page_bottom) {
  $route_match = \Drupal::routeMatch();

  if ($route_match->getRouteName() == 'block.admin_display_theme') {
    $region_list = system_region_list($route_match->getParameter('theme'), REGIONS_VISIBLE);
    $form_state = new FormState();
    $form_state->set('region_list', $region_list);
    $page_bottom['layout_control'] = \Drupal::formBuilder()->buildForm('\Drupal\block_ui\Form\LayoutControlForm', $form_state);
  }
}

Tags:

Forms

8