DEMOS / Live Component

Up & Down Voting

With each row as its own component, it's easy to add up & down voting + keep track of which items have been voted on. This uses a LiveAction to save everything with Ajax.

Banana ๐ŸŒ Votes: 33
Apple ๐ŸŽ Votes: 88
Hamburger ๐Ÿ” Votes: 92
Watermelon ๐Ÿ‰ Votes: 86
Cheese ๐Ÿง€ Votes: 41
Pizza ๐Ÿ• Votes: 77
Pretzel ๐Ÿฅจ Votes: 59
Donut ๐Ÿฉ Votes: 94
Pineapple ๐Ÿ Votes: 14
Popcorn ๐Ÿฟ Votes: 24
Egg ๐Ÿณ Votes: 7
Taco ๐ŸŒฎ Votes: 30
Ice Cream ๐Ÿฆ Votes: 32
Cookie ๐Ÿช Votes: 85
src/Twig/Components/FoodVote.php
// ... use statements hidden - click to show
use App\Entity\Food;
use App\Repository\FoodRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveAction;
use Symfony\UX\LiveComponent\Attribute\LiveArg;
use Symfony\UX\LiveComponent\Attribute\LiveProp;
use Symfony\UX\LiveComponent\DefaultActionTrait;

#[AsLiveComponent]
final class FoodVote extends AbstractController
{
    use DefaultActionTrait;

    #[LiveProp]
    public Food $food;

    #[LiveProp]
    public bool $hasVoted = false;

    public function __construct(private FoodRepository $foodRepository)
    {
    }

    #[LiveAction]
    public function vote(#[LiveArg] string $direction): void
    {
        if ('up' === $direction) {
            $this->food->upVote();
        } else {
            $this->food->downVote();
        }

        $this->foodRepository->add($this->food, true);
        $this->hasVoted = true;
    }
}
<tr {{ attributes }}>
    <th>{{ food.name }}</th>
    <td>
        Votes: {{ food.votes }}
    </td>
    <td style="width: 250px;">
        {% if hasVoted %}
            <twig:Alert variant="success">Thanks for voting!</twig:Alert>
        {% else %}
            <twig:Button
                variant="secondary"
                data-action="live#action"
                data-live-action-param="vote"
                data-live-direction-param="up"
            >
                <twig:ux:icon name="arrow-up" />
            </twig:Button>
            <twig:Button
                variant="secondary"
                data-action="live#action"
                data-live-action-param="vote"
                data-live-direction-param="down"
            >
                <twig:ux:icon name="arrow-down" />
            </twig:Button>
        {% endif %}
    </td>
</tr>
Author weaverryan
Published 2022-06-17