1

Any idea how I could to use my own custom module twig file to theme my table?

I'm using drupal/examples -> content_entity_example as a starting point:

in content_entity_example.module implementing hook_theme I would like to return all fields like:


/**
 * @file
 * Contains Drupal\content_entity_example\content_entity_example.module.
 */

/**
 * @defgroup content_entity_example Example: Content Entity
 * @ingroup examples
 * @{
 * Implement a content entity.
 *
 * This module demonstrates implementing a content entity.
 *
 * Entity API is the API that stores pieces of content and configuration for
 * Drupal core. For instance, if you've encountered node content types, you've
 * encountered entities of type 'node.'
 *
 * This example implements the Entity API so that we have an entity type usable
 * by the user which you might think of as specialized nodes, but which are
 * different from nodes. These entities are called Contact, and are known
 * internally by the machine name content_entity_example_contact.
 *
 * Contact is a fieldable content entity used to hold structured information
 * without the overhead of using a node content type. 'Fieldable' means you can
 * attach fields to it, like you can with nodes. It is defined programmatically
 * (completely in code). We will show the main techniques to handle and expose
 * the contents of this entity type.
 *
 * The Contact entity will demonstrate the main tasks for an entity:
 * - define
 * - save
 * - load
 * - view
 * - edit
 * - delete
 * - control access
 *
 * Where ever possible, we use the amazing tools built into D8 natively.
 *
 * @see Drupal\content_entity_example\Entity\Contact
 * @see config_entity_example
 * }
 */

/**
 * Implements hook_theme(). Register a module or theme's theme implementations.
 */

function content_entity_example_theme() {
  return [
    'content_entity_example_table' => [
      'variables' => [
        'header' => NULL,
        'rows' => NULL,
        'footer' => NULL,
        'attributes' => [],
        'caption' => NULL,
        'colgroups' => [],
        'sticky' => FALSE,
        'responsive' => TRUE,
        'empty' => ''
      ],
    ],
  ];
}

And in src/Entity/Controller/ContactListBuilder.php I would like to pickup my template ( '#template' ...)

So I would like to tell render() to user my template

  /**
   * {@inheritdoc}
   *
   * We override ::render() so that we can add our own content above the table.
   * parent::render() is where EntityListBuilder creates the table using our
   * buildHeader() and buildRow() implementations.
   */
  public function render() {
    $build['description'] = [
      '#markup' => $this->t('Content Entity Example implements a Contacts model. These contacts are fieldable entities. You can manage the fields on the <a href="@adminlink">Contacts admin page</a>.', [
        '@adminlink' => $this->urlGenerator->generateFromRoute('content_entity_example.contact_settings'),
      ]),
    ];
    $build['table'] = parent::render();

// TODO add template reference

    return $build;
  }

and as such use my template file in /templates/content-entity-example.html.twig which is going to be changed in a later phase. (just need to get it loaded)

{#
/**
 * @file
 * Theme override to display a table.
 *
 * Available variables:
 * - attributes: HTML attributes to apply to the <table> tag.
 * - caption: A localized string for the <caption> tag.
 * - colgroups: Column groups. Each group contains the following properties:
 *   - attributes: HTML attributes to apply to the <col> tag.
 *     Note: Drupal currently supports only one table header row, see
 *     https://www.drupal.org/node/893530 and
 *     http://api.drupal.org/api/drupal/includes!theme.inc/function/theme_table/7#comment-5109.
 * - header: Table header cells. Each cell contains the following properties:
 *   - tag: The HTML tag name to use; either 'th' or 'td'.
 *   - attributes: HTML attributes to apply to the tag.
 *   - content: A localized string for the title of the column.
 *   - field: Field name (required for column sorting).
 *   - sort: Default sort order for this column ("asc" or "desc").
 * - sticky: A flag indicating whether to use a "sticky" table header.
 * - rows: Table rows. Each row contains the following properties:
 *   - attributes: HTML attributes to apply to the <tr> tag.
 *   - data: Table cells.
 *   - no_striping: A flag indicating that the row should receive no
 *     'even / odd' styling. Defaults to FALSE.
 *   - cells: Table cells of the row. Each cell contains the following keys:
 *     - tag: The HTML tag name to use; either 'th' or 'td'.
 *     - attributes: Any HTML attributes, such as "colspan", to apply to the
 *       table cell.
 *     - content: The string to display in the table cell.
 *     - active_table_sort: A boolean indicating whether the cell is the active
         table sort.
 * - footer: Table footer rows, in the same format as the rows variable.
 * - empty: The message to display in an extra row if table does not have
 *   any rows.
 * - no_striping: A boolean indicating that the row should receive no striping.
 * - header_columns: The number of columns in the header.
 *
 * @see template_preprocess_table()
 */
#}
<table{{ attributes }}>
  {% if caption %}
    <caption>{{ caption }}</caption>
  {% endif %}

  {% for colgroup in colgroups %}
    {% if colgroup.cols %}
      <colgroup{{ colgroup.attributes }}>
        {% for col in colgroup.cols %}
          <col{{ col.attributes }} />
        {% endfor %}
      </colgroup>
    {% else %}
      <colgroup{{ colgroup.attributes }} />
    {% endif %}
  {% endfor %}

  {% if header %}
    <thead>
    <tr>
      {% for cell in header %}
      {%
        set cell_classes = [
        cell.active_table_sort ? 'is-active',
      ]
      %}
      <{{ cell.tag }}{{ cell.attributes.addClass(cell_classes) }}>
      {{- cell.content -}}
    </{{ cell.tag }}>
    {% endfor %}
    </tr>
    </thead>
  {% endif %}

  {% if rows %}
    <tbody>
    {% for row in rows %}
      {%
        set row_classes = [
        not no_striping ? cycle(['odd', 'even'], loop.index0),
      ]
      %}
    <tr{{ row.attributes.addClass(row_classes) }}>
      {% for cell in row.cells %}
        <{{ cell.tag }}{{ cell.attributes }}>
        {{- cell.content -}}
        </{{ cell.tag }}>
      {% endfor %}
      </tr>
    {% endfor %}
    </tbody>
  {% elseif empty %}
    <tbody>
    <tr class="odd">
      <td colspan="{{ header_columns }}" class="empty message">{{ empty }}</td>
    </tr>
    </tbody>
  {% endif %}
  {% if footer %}
    <tfoot>
    {% for row in footer %}
    <tr{{ row.attributes }}>
      {% for cell in row.cells %}
        <{{ cell.tag }}{{ cell.attributes }}>
        {{- cell.content -}}
        </{{ cell.tag }}>
      {% endfor %}
      </tr>
    {% endfor %}
    </tfoot>
  {% endif %}
</table>

content_entity_example works great but I can't load my own template.

1
  • From the code isn't clear which method is parent::render() calling, since we don't know which is the parent class.
    – apaderno
    Dec 28 '21 at 9:00
0

It should be as simple as setting the #theme on the table that parent::render() returns:

$build = parent::render();
$build['table']['#theme'] = 'content_entity_example_table';
2
  • thanks, my twig file gets called, but if I do {{ kint(header) }} in my custom twig, it's empty. If I disable my theme() function, the default drupal theme gets called which has a header. so I suppose my custom theme() function isn't properly configured. I can't seem to find the docs for correct settings. Dec 23 '21 at 1:37
  • $build['table']['#theme'] = 'table__content_entity_example'; which is defined in theme() as 'base hook' => 'table'.
    – 4k4
    Dec 23 '21 at 22:06

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.