Integració de Javascript i Symfony
Junt al bundle Encore s'instal·la suport per a Stimulus, un framework lleuger JavaScript que fa fàcil adjuntar comportament a HTML. A més Symfony inclou paquets per afegir més característiques a Stimulus.
El propòsit del fitxer assets/bootstrap.js
és inicialitzar Stimulus i carregar
automàticament qualsevol "controlador" del directori assets/controllers/
.
Cas d'ús: fer m'agrada
L'objectiu és implementar la funcionalitat de M'agrada amb Javascript, usant
el mètode fetch
.
Primerament crearem una interacció simple en què en fer M'agrada s'incrementarà el comptador de likes.
Pas 1: Controlador stimulus
El següent codi afig un esdeveniment que en fer clic sobre l'element
associat incrementa el comptador de likes i l'escriu en el target count
.
import { Controller } from '@hotwired/stimulus';
/*
* The following line makes this controller "lazy": it won't be downloaded until needed
* See https://github.com/symfony/stimulus-bridge#lazy-controllers
*/
/* stimulusFetch: 'lazy' */
export default class extends Controller {
static targets = ['count']
connect() {
this.count = 0;
this.element.addEventListener('click', (event) => {
this.count++;
this.countTarget.innerText = this.count;
event.preventDefault();
});
}
// ...
}
L'array targets
inclou els elements vàlids sobre els quals volem actuar i
el mètode connect()
s'executa automàticament quan s'assigna el controlador
a qualsevol element.
Pas 2: Adaptació de la vista
Afegirem els atributs data-controler
amb el nom del controlador i data-like-target
amb el nom
amb què volem identificar l'element que modificarem des del controlador, count
en l'exemple.
<div data-controller="like" class="pe-5">
{% if app.user not in truit.linkingUsers %}
<a title="M'agrada" href="{{ path('tweet_like', { id: truit.id }) }}"><i class="bi bi-heart"></i></a>
{% else %}
<i class="text-danger bi bi-heart-fill"></i>
{% endif %}
<span data-like-target="count" class="ms-1">{{ truit.likeCount }}</span>
</div>
Pas 3. Creació de l'endpoint
Farem una versió del mètode like
que en lloc de fer una redirecció retornarà
una resposta en format JSON.
#[Route('/api/tweets/{id}/like', name: 'api_tweet_like')]
public function apiLike(Tweet $tweet, TweetRepository $tweetRepository): Response {
$user = $this->getUser();
if (!$user)
return new JsonResponse(["result"=>"ko"], Response::HTTP_UNAUTHORIZED);
if ($tweet->getLinkingUsers()->contains($user))
return new JsonResponse(["result"=>"ko"], Response::HTTP_OK);
$tweet->addLinkingUser($user);
$tweet->setLikeCount($tweet->getLikeCount() + 1);
$tweetRepository->save($tweet, true);
return new JsonResponse(["result"=>"ok"], Response::HTTP_OK);
}
Pas 4: Adaptació de la vista
Afegirem l'atribut data-like-url-value
amb la URL de l'endpoint i un nou target
anomenat icon
, aquest ens permetrà modificar la icona.
<div data-controller="like"
data-like-url-value="{{ path('api_tweet_like', { id: truit.id }) }}" class="pe-5">
{% if app.user not in truit.linkingUsers %}
<a title="M'agrada" data-like-target="icon" href="{{ path('tweet_like', { id: truit.id }) }}"><i class="bi bi-heart"></i></a>
{% else %}
<i class="text-danger bi bi-heart-fill"></i>
{% endif %}
<span data-like-target="count" class="ms-1">{{ truit.likeCount }}</span>
</div>
Pas 5: Versió final del controlador
import { Controller } from '@hotwired/stimulus';
/*
* The following line makes this controller "lazy": it won't be downloaded until needed
* See https://github.com/symfony/stimulus-bridge#lazy-controllers
*/
/* stimulusFetch: 'lazy' */
export default class extends Controller {
static targets = ['count', 'icon']
static values = {
url: String,
}
connect() {
this.count = 0;
this.element.addEventListener('click', (event) => {
this.load();
event.preventDefault();
console.log(this.urlValue);
});
}
load() {
fetch(this.urlValue)
.then(response => response.json())
.then(data => this.update(data))
}
update(data) {
if (data.result === "ok") {
this.count++;
this.countTarget.innerText = this.count;
this.iconTarget.innerHTML = "<i class=\"text-danger bi bi-heart-fill\"></i>";
}
}
// ...
}
Recursos
https://symfony.com/doc/current/frontend/encore/simple-example.html#stimulus-symfony-ux https://symfonycasts.com/screencast/stimulus/properties-events https://stimulus.hotwired.dev/