12

I am fairly new to Drupal 8 module development, so I decided to follow a tutorial at https://docs.acquia.com/articles/drupal-8-creating-elements-theming-elements-and-managing-frontend-libraries, which describes the process of setting up a module with a render element using a twig template. I followed the code exactly and have included the sections I'm working on below (I did not include the info and routing code).

I am seeing my controller return the correct elements, however I am unable to see the twig template render with additional markup. From what I understand the element 'my_element' should be getting returned from the controller's second element in the render array ... 'type'=>'my_element'. Also my_element is defined in hook_theme in the module file but I think I am getting confused on how this links to the template called my-element.html.twig. Can anyone provide any tips or suggestions?

theme_example.module

<?php

/**
* Implements hook_theme().
*/
function theme_example_theme() {
  $items = [
    'my_element' => [
      'render element' => 'element',
    ],
  ];
  return $items;
}

src/Controller/ThemeExampleController.php

<?php
/**
 * @file
 * Contains \Drupal\theme_example\Controller\ThemeExampleController.
 */

namespace Drupal\theme_example\Controller;

use Drupal\Core\Controller\ControllerBase;

/**
 * Controller routines for theme example routes.
 */
class ThemeExampleController extends ControllerBase {

  public function simple() {
    return [
      'example one' => [
        '#markup' => '<div>Markup Example</div>',
      ],
      'example two' => [
        '#type' => 'my_element',
        '#label' => $this->t('Example Label'),
        '#description' => $this->t('This is the description text.'),
      ],
    ];
  }
}

src/Element/MyElement.php

<?php
/**
 * @file
 * Contains \Drupal\theme_example\Element\MyElement.
 */

namespace Drupal\theme_example\Element;

use Drupal\Core\Render\Element\RenderElement;
use Drupal\Core\Url;

/**
 * Provides an example element.
 *
 * @RenderElement("my_element")
 */
class MyElement extends RenderElement {
  /**
   * {@inheritdoc}
   */
  public function getInfo() {
    $class = get_class($this);
    return [
      '#theme' => 'my_element',
      '#label' => 'Default Label',
      '#description' => 'Default Description',
      '#pre_render' => [
        [$class, 'preRenderMyElement'],
      ],
    ];
  }

  /**
   * Prepare the render array for the template.
   */
  public static function preRenderMyElement($element) {
    // Create a link render array using our #label.
    $element['link'] = [
      '#type' => 'link',
      '#title' => $element['#label'],
      '#url' => Url::fromUri('http://www.drupal.org'),
    ];

    // Create a description render array using #description.
    $element['description'] = [
      '#markup' => $element['#description']
    ];

    $element['pre_render_addition'] = [
      '#markup' => 'Additional text.'
    ];

    // Create a variable.
    $element['#random_number'] = rand(0,100);

    return $element;
  }
}

templates/my-element.html.twig

{#
/**
 * @file
 * Default theme implementation to my_element.
 *
 * Available variables:
 * - element: Element that will be rendered.
 * - element['link'] : a link
 * - element['description'] : a description
 * - element['pre_render_addition'] : added during the #pre_render function
 * - element['random_number'] : a random number variable, won't be printed with the element.
 *
 * @ingroup themeable
 */
#}

<div class="myElement">
  <div class="randomNumber">Random Number: {{ element['#random_number'] }}</div>
  <p>{{ element.description }}</p>
  {{ element.link }}
</div>

{# Debug output #}
<div>
  <h3>We print the element</h3>
  {{ element }}
  <h3>Link</h3>
  {{ element.link }}
  <h3>Description</h3>
  {{ element.description }}
  <h3>#pre_render addition</h3>
  {{ element.pre_render_addition }}
  <h3>Random number (not printed when we printed the whole element</h3>
  {{ element['#random_number'] }}
</div>
1
  • 4
    Not seeing any issues in your code, have you tried to rebuild cache?
    – FLY
    Sep 15, 2021 at 9:56

2 Answers 2

1

Your code is correct. Explaining the flow below:

The key for item in the array is what you will need to call the template And the key is : my_element

<?php

/**
* Implements hook_theme().
*/
function theme_example_theme() {
  $items = [
   'my_element' => [
   'render element' => 'element',
    ],
  ];
  return $items;
 }

Then creating twig template and replacing underscores with dashes like this : my-element.html.twig under templates folder. By render element which is 'element' ,calling each field. After creating both the file , where you are returning your render array make a call to your twig template. which is below:

class MyElement extends RenderElement {
/**
* {@inheritdoc}
*/
public function getInfo() {
  $class = get_class($this);
   return [
    '#theme' => 'my_element',
    '#label' => 'Default Label',
    '#description' => 'Default Description',
    '#pre_render' => [
       [$class, 'preRenderMyElement'],
     ],
   ];
 }

Then using the key my_element in controller for fetching all from preRenderMyElement().

 public function simple() {
   return [
     'example one' => [
     '#markup' => '<div>Markup Example</div>',
     ],
     'example two' => [
     '#type' => 'my_element',
     '#label' => $this->t('Example Label'),
     '#description' => $this->t('This is the 
      description 
      text.'),
      ],
    ];
  }
0

All your code works.

I created your module, adding a routes and info file to make it work, enabled it, visited /theme-example and I could see you template was being used.

See https://github.com/dahousecat/theme-example for the whole module.

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.