Rendering Components

To render a Wire component on a page use the wire() Twig function

<div>

  ...
  
  {{ wire('related_articles') }}
  
  ...
  
</div>

Or, if you're in the context of a rend-arable array e.g Form, Controller, you can use wire render element

$build['related_articles'] = [
  '#type' => 'wire',
  '#id' => 'related_articles',
];

Note: Ensure that the module in which the component has been generated is enabled

You can pass data into a component by passing additional parameters into the wire() function.

For example, let's say we have a "related_articles" component we want to include via Node's node.html.twig template. Here's how you would pass in the the ID of Node entity object.

{{ wire('related_articles', {'nodeId': node.id}) }}

When using wire render element you would do

$build['related_articles'] = [
  '#type' => 'wire',
  '#id' => 'related_articles',
  '#context' => ['nodeId' => 999],
];

 

Wire will automatically assign parameters to matching public properties.

Make sure to read Properties section to align your expectations.

For example, in the case of wire('related_nodes', {'nodeId': node.id}), if the respective component has a public property named $nodeId, it will be automatically assigned and persist between Wire updates:

use Drupal\wire\WireComponent;
/**
 * @WireComponent(
 *   id = "related_articles",
 *   label = @Translation("Related Articles"),
 * )
 */
class RelatedArticles extends WireComponent {
  public ?int $nodeId;
  
  ...
}

If for whatever reason, this automatic behavior doesn't work, you can intercept parameters using the mount() method.

use Drupal\node\Entity\Node;
use Drupal\wire\WireComponent;

/**
 * @WireComponent(
 *   id = "related_articles",
 *   label = @Translation("Related Articles"),
 * )
 */
class RelatedArticles extends WireComponent {

  public ?int $nodeId;
  
  public string $label;  
  
  public function mount($nodeId) {
    $this->label = 'Related articles for: ' . Node::load($nodeId)->label();
  }
}

The mount() method is only called when the component is first mounted and will NOT be called again when the component is refreshed or re-rendered. Think of it as a class __construct() method.

At this point you might wonder if you can pass in the whole Node entity object.

The answer is yes but, with a caveat. When you pass any unsupported property it can be intercepted in the mount() method but it won't persist during Wire updates.

{{ wire('related_articles', {'node': node}) }}

In the PHP class:

use Drupal\node\Entity\Node;
use Drupal\wire\WireComponent;

/**
 * @WireComponent(
 *   id = "related_articles",
 *   label = @Translation("Related Articles"),
 * )
 */
class RelatedArticles extends WireComponent {

  protected ?Node $node;  
  
  public string $label;  
  
  public function mount(?Node $node) {
    $this->node = $node;
  }
  
  public function render(): ?View {
    // $this->node is available here but only on the initial load.
  }
}

 

A Wire component's render method gets called on the initial page load and every subsequent component update.

The render() method is expected to return an instance of Drupal\wire\View which has a few different ways to get its HTML.

Here is an example using View::fromTpl():

Make sure your Twig template only has ONE root element.

public function render(): ?View {

    return View::fromTpl('articles', [
      'articles' => Node::loadMultiple(),
    ]);
  
}

/wiredemo/templates/wire/articles.html.twig

<div>
    {% for article in articles %}
  
        <h2>{{ article.label }} </h2>
    
    {% endfor %}
</div>

The  ::fromTpl() method, expects the filename without its extension part which must be located in a templates/wire/ directory of a module or theme. The priority of loading the template is: active theme ?-> parent/base theme(s) ?-> module.

 

If you don't want to use a twig file at all, you can return a template string directly from render() method

public function render(): ?View {
  $twig = <<<'TWIG'
    <div>
      {% for article in articles %}
      
        <h2>{{ article.label }} </h2>
        
      {% endfor %}
    </div>
  TWIG;
  
  return View::fromString($twig);
}

 

You might want to render using Theme Implementations(hook_theme), Render elements, ...

This can be achieved with render_var function.

E.g:

public function render(): ?View {

  $rendarableEl = [
    '#type' => 'theme',
    '#theme' => 'my_theme_accepting_dynamic_value',
    '#my_dynamic_value' => $this->dynamicValue,
  ];

  $twig = <<<'TWIG'
    <div>
      {{ render_var(rendarableEl) }}
      <hr />
      <p>{{ my_dynamic_value }}</p>
    </div>
  TWIG;

  return View::fromString($twig, [
    'my_dynamic_value' => $this->count,
    'rendarableEl' => $rendarableEl],
  );
}
********************************** ************************* ************************ **************** ****************** *********** ************** ************* ************ *************