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],
);
}