3

I created a simple custom module where I created a Class Form using a custom template form. If I don't use my custom template (I comment my _theme hook from my .module), when I submit my form, class methods handlers validate and submit are called. But When I use my custom form template, If I submit my form, validate and submit class methods handlers aren't called, I don't understand why.

This is my code; I begin with my templates/form--myformtest-form.html.twig template.

<h1>TEST</h1>
<form{{ element }}></form>

My myformtest.module code is the following.

/**
 * Implements hook_theme().
 */
function myformtest_theme($existing, $type, $theme, $path)
{
  return array(
    'form__myformtest_form' => array(
      'render element' => 'form',
      'template' => 'form--myformtest-form',
    ),
  );
}

If I comment this hook, my form use the default theme form template. In this case, submit the form call validate and submit class handlers methods. If I don't comment this hook, my form use my custom template. Then when I access to my custom form page and valid the form, validate and submit handler are never called.

This is the simple code from my src/Form/MyformtestForm.php class.

class MyformtestForm extends FormBase {
  //...
  public function buildForm(array $form, FormStateInterface $form_state) {
    $form['textfieldtest'] = [
      '#type' => 'textfield',
      '#title' => $this->t('textfieldtest'),
      '#maxlength' => 64,
      '#size' => 64,
    ];

    $form['submit'] = [
        '#type' => 'submit',
        '#value' => t('Submit'),
    ];

    return $form;
  }

  public function validateForm(array &$form, FormStateInterface $form_state) {
    ksm("MyformtestForm Validate handler!");
    // logs never displayed when I use my custom template. If I don't use the custom template, this log appears.
  }

  public function submitForm(array &$form, FormStateInterface $form_state) {
    ksm("MyformtestForm Submit handler");
    // logs never displayed when I use my custom template. If I don't use the custom template, this log appears.
  }

Why handlers aren't called when my form use my custom override? How can I call them?

These are the variables existing from my custom template when I load my form page.

screenshot

1
  • I haven't yet worked with D8 enough to give a specific answer, but it looks like you probably aren't rendering the hidden elements that come with every form, that identify the form ID and a few other things that are required for the Form API to work (and call your handlers). In Drupal 7, after rendering your various elements on the page, you would at the end call render($form) that would render any remaining (and hidden) for elements, allowing for the form to work. I don't know how you would do that in D8, but this may point you in the right direction.
    – Jaypan
    Sep 30, 2016 at 6:11

4 Answers 4

3
+50

You need "base hook" in there, I believe.

Here's an example:

/**
 * Implements hook_theme().
 */
function formcustomtemplate_theme() {
  return array(
    'form__my_form_test' => array(
      'render element' => 'form',
      'template' => 'form--myformtest-form',
      'base hook' => 'form',
    ),
  );
}

If you are using a custom theme, and you don't need the template in your module, the approach of creating a new theme hook for your custom form is unnecessary.
Rather than create a new theme hook, use hook_theme_suggestions_alter in your theme:

/**
 * Implements hook_theme_suggestions_alter().
 */
function mytheme_theme_suggestions_alter(array &$suggestions, array $variables, $hook) {

  if ($hook == 'form' & !empty($variables['element']['#theme'])) {
    $suggestions[] = 'form__' . $variables['element']['#theme'][0];
  }

}

then create the appopriate template in your theme.

then to see the theme suggestions output to the page, turn on twig debugging:

https://drupalize.me/blog/201405/lets-debug-twig-drupal-8

You'll see template suggestions in the markup:

<!-- FILE NAME SUGGESTIONS:
   * form--myformtest-form.html.twig
   x form.html.twig
-->

You can see that it's not yet picking up your template, so create a template file by copying the form.html.twig and renaming it.

To check where Drupal is looking for templates using the "form" hook, you can print out the theme registry from hook_theme_registry_alter:

 "form" => array:6 [▼
    "template" => "form"
    "path" => "themes/custom/mycustomtheme/templates/form"
    "type" => "theme_engine"
    "theme path" => "themes/custom/mycustomtheme”
    "render element" => "element"
    "preprocess functions" => array:4 [ …4]

This lets you know that you need to put the template in that directory.

8
  • Yes, I used the theme_suggestions_alter hook for find the good name of the template, I get it from the code of the page, its name is "form--myformtest-form" and I used it from my _theme hook (I remplaced '-' chars by '' chars). If I use only "_theme_suggestions_alter", my form doesn't use my custom template. I think the hook _theme_suggestions_alter serves only to show suggestion(s), this hook doen't link the custom theme with the custom form. With your twig code, the form doesn't appears. Then I replaced "attributes" by "element" in for tag, but submit form doesn't call its handlers.. Sep 30, 2016 at 20:53
  • However, I didn't use controller Class in my module. My routing uses the form Class directly. Ill try with add a controller. Sep 30, 2016 at 20:56
  • I generated a (very) simple controller via the Drupal console. From my controller, I return my form like this "return \Drupal::formBuilder()->getForm('...')". My page display the form, but when I submit its, handlers aren't called :/ I show existing variables in the page when I go to the url using the Controller. There are almost no difference when I go to url using the form directly (no Controller Class used) Sep 30, 2016 at 21:35
  • 1
  • 1
    After noticing that my approach doesn't work with the template in the custom module, I revised the code in the example above to use hook_theme, as you were originally trying to do. I looked at some examples and noticed they had "base hook", so I added that. Anyway, it's working and firing the validate hook. See the code example above.
    – oknate
    Oct 3, 2016 at 17:03
1

This might prove useful for people who want to style each element of the form.

/**
 * Implements hook_form_BASE_FORM_ID_alter().
 */

function MODULE_NAME_form_YOUR_FORM_ID_alter(&$form, FormStateInterface &$form_state) {
  $form['#theme'] = ['CUSTOM_NAME'];
}

Afterwards I set up my hook with the needed element.

/**
 * Implements hook_theme().
 */
function MODULE_NAME_theme($existing, $type, $theme, $path) {
  return [
    'CUSTOM_NAME' => [
      'render element' => 'form',
    ],
  ];
}

I named my template accordingly(CUSTOM_NAME.html.twig). Here, you can render your $form elements accordingly(ex: {{ form.name }}, coming from $form['name']).

And last but BELIEVE ME, not least, and most importantly, do not forget to include the form_build_id and form_token variables.

  {{ form.form_build_id }} {# required #}
  {{ form.form_id }} {# required #}
  {{ form.form_token }} {# required #}

The answer to the question is already chosen, this one is just a simple as it gets explanation for how to theme your form more thoroughly.

Cheers

0

I also think that the rendering of your form is the problem. Take a look at the default form templates in core, like form.html.twig.

https://api.drupal.org/api/drupal/core!modules!system!templates!form.html.twig/8.2.x

May you try it in that way and use {{ children }} or render the fields step by step with something like {{ element.textfieldtest }}.

So I would use this code

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

You can also dump the output in the template with {{ dump }} and look which variables you have. Here is a link for enabling the twig debugging https://www.drupal.org/docs/8/theming/twig/debugging-twig-templates

1
  • I already try to find the solution with variables dumping ( {{ dump }} and {{ kint }} ). But I didn't find the solution... I started with the code of the default form template, but same, its doesn't work :/ (form not displayed !) Sep 30, 2016 at 20:36
0

if you worked with drupal 7 , in drupal 7 we render drupal_render_children($form); in our markups to drupal render hidden and csrf fields, According to From.html.twig

Available variables

attributes: A list of HTML attributes for the wrapper element.
children: The child elements of the form.

if you want first render the elements as you want then you should finally render {{ children}} as drupal 7 method.

So first render your desire elements then render {{ children }},your should try something like

<h1>TEST</h1>
<div class="myclass">{{ element }} </div>
// other elements
// and finally
{{ children }}
1
  • With your code when I click on the submit button of my form, nothing happened (no submission). I also tested "<div class="myclass"><form{{ element }}></form></div>{{ children }}", when I submit the form, its handlers aren't called. And I also tested "<form{{ element }}>{{ children }}</form>", same result, when I submit the form, its handlers aren't called. initially, I started with the default form template, but copy it doesn't work.. Sep 30, 2016 at 20:29

Your Answer

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

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