seaworn/symfony-htmx-bundle

Htmx integration for Symfony

Installs: 14

Dependents: 0

Suggesters: 0

Security: 0

Stars: 3

Watchers: 2

Forks: 1

Open Issues: 0

Type:symfony-bundle

dev-main 2024-01-10 22:28 UTC

This package is auto-updated.

Last update: 2024-09-10 23:50:26 UTC


README

Htmx integration for Symfony

  • Symfony >=6.0
  • PHP >=8.0

Install

$ composer require seaworn/symfony-htmx-bundle

Setup

Add the following snippet to the front controller. This will allow Symfony to use a custom Request class

/* public/index.php */

\Symfony\Component\HttpFoundation\Request::setFactory(function (...$args) {
    return new \Seaworn\HtmxBundle\Request\HtmxRequest(...$args);
});

Usage

Extend your controller from Seaworn\HtmxBundle\Controller\AbstractController or use the Seaworn\HtmxBundle\Controller\HtmxControllerTrait trait

// ...
use Seaworn\HtmxBundle\Request\HtmxRequest;
use Seaworn\HtmxBundle\Response\HtmxResponse;

class HelloController extends \Seaworn\HtmxBundle\Controller\AbstractController{}

// or

class HelloController extends \Symfony\Bundle\FrameworkBundle\Controller\AbstractController
{
    use \Seaworn\HtmxBundle\Controller\HtmxControllerTrait;
}

Request headers

public function index(HtmxRequest $request): HtmxResponse
{
    // whether the request is made via htmx
    $request->isHtmxRequest();

    // whether the request is via an element using hx-boost attribute
    $request->isBoosted();
    
    // the current browser url
    $request->getCurrentUrl();
    
    // whether request is for history restoration after a miss in the local history cache
    $request->isHistoryRestoreRequest();
    
    // the user response to an hx-prompt
    $request->getPromptResponse();
    
    // the id of the target element if it exists
    $request->getTargetId();

    // the id of the triggered element if it exists
    $request->getTriggerId();
    
    // the name of the triggered element if it exists
    $request->getTriggerName();
    
    // ...
}

Response headers

public function index(HtmxRequest $request): HtmxResponse
{
    // ...

    return $this->htmxRender('index.html.twig') // or new HtmxResponse()
        // Optional headers
        ->setLocation(
            "/location", 
            [
              'source' => '',
              'event' => '',
              'handler' => '',
              'target' => '',
              'swap' => '',
              'select' => ''
              'values' => [],
              'headers' => [],
            ]
        )) // set HX-Location header
        ->setPushUrl('/push') // set HX-Push-Url header
        ->setReplaceUrl('/replace') // set HX-Replace-Url header
        ->setReswap('outerHTML') // set HX-Reswap header
        ->setRetarget('#target') // set HX-Retarget header
        ->setReselect('#select') // set HX-Reselect header
        ->setTriggers('event') // set HX-Trigger header (simple)
        ->setAfterSwapTriggers('event1,event2') // set HX-Trigger-After-Swap header (multiple)
        ->setAfterSettleTriggers(['event' => ['key' => 'value']]); // set HX-Trigger-After-Settle header (with detail)
}

Render template block

<!-- index.html.twig -->

{% extends 'base.html.twig' %}

{% block block1 %}
    <div id="block1"> 
        Sample content...
    </div>
{% endblock %}
public function index(HtmxRequest $request): HtmxResponse
{
    return $this->htmxRenderBlock('index.html.twig', 'block1');
}

Redirect

public function index(HtmxRequest $request): HtmxResponse
{
    return $this->htmxRedirect('https://htmx.org/');
}

Refresh

public function index(HtmxRequest $request): HtmxResponse
{
    return $this->htmxRefresh();
}

Stop polling

<!-- index.html.twig -->

{% extends 'base.html.twig' %}

{% block content %}
    <div hx-get="/poll" hx-vals="js:{pollingIndex}" hx-trigger="every 2s"></div>
    <script type="text/javascript">
        var pollingIndex = 0;
        document.body.addEventListener("polling", function(e) {
            pollingIndex++;
            console.log("Polling Index:", pollingIndex);
        });
    </script>
{% endblock %}
public function poll(HtmxRequest $request): HtmxResponse
{ 
    $index = $request->get('pollingIndex', 0);
    if ((int)$index >= 10) {
        return new HtmxStopPollingResponse();
    }
    return (new HtmxResponse())->setTriggers('polling');
}