-1

I'm trying to render limited user edit form on custom page using Drupal Controller. In the routing.yml I defined _controller, I do not want to use _form.

I want to display on the form e.g. only timezone field, but not the rest. And I'm not able to achieve it. I can render this field, other fields like form_build_id, form_id, form_token But form html tag is not rendered at all. It works only if I display the whole form with {{ form.form }}.

This is the content of the files I am using.

my_module.info.yml

name: 'My module'
type: module
description: 'my module'
core_version_requirement: ^8.8 || ^9

my_module.routing.yml

my_module.mymodule_controller_view::
  path: '/my-module'
  defaults:
    _controller: '\Drupal\my_module\Controller\MymoduleController::view'
    _title: 'My module'
  requirements:
    _permission: 'access content'

my_module.module

function my_module_theme($existing, $type, $theme, $path)
{
    $templates = array(
        'my_module_form' => [
            'render element' => 'form',
        ],
    );

    return $templates;
}

MymoduleController.php

namespace Drupal\my_module\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\user\Entity\User;

class MymoduleController extends ControllerBase
{

    public function view()
    {
        $data['header'] = [
            '#type' => 'markup',
            '#markup' => '<h1>HEADER</h1>',
        ];

        $user = User::load(\Drupal::currentUser()->id());
        $formObject = \Drupal::entityTypeManager()
            ->getFormObject('user', 'default')
            ->setEntity($user);

        $form = \Drupal::formBuilder()->getForm($formObject);

        $data['form'] = [
            '#theme' => 'my_module_form',
            'form' => $form,
        ];

        $data['footer'] = [
            '#type' => 'markup',
            '#markup' => '<h3>footer</h3>',
        ];

        return $data;
    }
}

my-module-form.html.twig

<div>TWIG TEMPLATE</div>

{{ form.form.timezone }}
{{ form.form.form_build_id }}
{{ form.form.form_token }}
{{ form.form.form_id }}
{{ form.form.actions }}
2

This is not working, you can't use a form template in a controller. You have to assign the template to $form['#theme'] when building the form or in a form alter hook. Then it gets used by formBuilder()->getForm() automatically.

See for example seven_form_node_form_alter():

$form['#theme'] = ['node_edit_form'];

and the corresponding twig file for a two column layout:

core/themes/seven/templates/node-edit-form.html.twig

{#
/**
 * @file
 * Theme override for a node edit form.
 *
 * Two column template for the node add/edit form.
 *
 * This template will be used when a node edit form specifies 'node_edit_form'
 * as its #theme callback.  Otherwise, by default, node add/edit forms will be
 * themed by form.html.twig.
 *
 * Available variables:
 * - form: The node add/edit form.
 *
 * @see seven_form_node_form_alter()
 */
#}
<div class="layout-node-form clearfix">
  <div class="layout-region layout-region-node-main">
    {{ form|without('advanced', 'footer', 'actions') }}
  </div>
  <div class="layout-region layout-region-node-secondary">
    {{ form.advanced }}
  </div>
  <div class="layout-region layout-region-node-footer">
    <div class="layout-region-node-footer__content">
      {{ form.footer }}
      {{ form.actions }}
    </div>
  </div>
</div>

Form modes

A different approach would be to configure a form mode in UI containing only the field you want and then use it in your controller:

    $formObject = \Drupal::entityTypeManager()
        ->getFormObject('user', 'custom_form_mode')
        ->setEntity($user);

See How do I load a form with a specific form display (form mode)?

| improve this answer | |
  • Thank you @4k4 very much!! This code $form['#theme'] in hook_theme() (used in module, not theme) helped. But with this user_edit form I have now another problem. I'm displaying only field timezone, but after saving it resets my roles. Other values (mail, custom fields) seems to be untouched. Any idea why? – Bohus Ulrych Jul 23 at 9:43
  • 1
    Normally values not submitted by a form element should not be overwritten. But I've seen in the edited question that you render {{ form.account.roles }} – 4k4 Jul 23 at 12:02
  • Maybe it was just my mistake, I do not have {{ form.account.roles }} in my twig. Standard user doesn't overwrite roles when submitting this form, but as admin user I will reset all my roles. Maybe this is bug in Drupal? ------------ Hm, I don't know what happened but my update is gone :-( – Bohus Ulrych Jul 24 at 9:41
  • This is what was missing: function my_module_form_alter(&$form, FormStateInterface $form_state, $form_id) { if ($form_id == 'user_form') { $form['#theme'] = ['my_module_about_form']; } } – Bohus Ulrych Aug 10 at 5:48

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.