diff --git a/README.md b/README.md
index 2ea2b14..516fa40 100644
--- a/README.md
+++ b/README.md
@@ -113,6 +113,123 @@ document.body.addEventListener('htmx:configRequest', (event) => {
})
```
+## Examples
+
+### Users index search functionality
+
+In this example, we will implement a search functionality for the users' index using Htmx to filter results dynamically. We will wrap our table body inside a [viewBlock](https://book.cakephp.org/5/en/views.html#using-view-blocks) called `usersTable`. When the page loads, we will render the `usersTable` [viewBlock](https://book.cakephp.org/5/en/views.html#using-view-blocks).
+
+```php
+// Template/Users/index.php
+
+= $this->Form->control('search', [
+ 'label' => false,
+ 'placeholder' => __('Search'),
+ 'type' => 'text',
+ 'required' => false,
+ 'class' => 'form-control input-text search',
+ 'value' => !empty($search) ? $search : '',
+ 'hx-get' => $this->Url->build(['controller' => 'Users', 'action' => 'index']),
+ 'hx-trigger' => "keyup changed delay:200ms",
+ 'hx-target' => "#search-results",
+ 'templates' => [
+ 'inputContainer' => '
{{content}}
'
+ ]
+]); ?>
+
+
+
+
+ = 'id' ?> |
+ = 'Name' ?> |
+ = 'Email' ?> |
+ = 'Modified' ?> |
+ = 'Created' ?> |
+ = __('Actions') ?> |
+
+
+
+
+ start('usersTable'); ?>
+
+
+ = $user->id ?> |
+ = h($user->name) ?> |
+ = h($user->email) ?> |
+ = $user->modified ?> |
+ = $user->created ?> |
+
+ = $this->Html->link('Edit',
+ [
+ 'action' => 'edit',
+ $user->id
+ ],
+ [
+ 'escape' => false
+ ]
+ ); ?>
+ = $this->Form->postLink('Delete',
+ [
+ 'action' => 'delete',
+ $user->id
+ ],
+ [
+ 'confirm' => __('Are you sure you want to delete user {0}?', $user->email),
+ 'escape' => false
+ ]
+ ); ?>
+ |
+
+
+ end(); ?>
+
+ fetch('usersTable'); ?>
+
+
+```
+In out controller we will check if the request is Htmx and if so then we will only render the `usersTable` [viewBlock](https://book.cakephp.org/5/en/views.html#using-view-blocks).
+
+```php
+// src/Controller/UsersController.php
+
+public function index()
+{
+ $search = null;
+ $query = $this->Users->find('all');
+
+ if ($this->request->is('get')) {
+ if(!empty($this->request->getQueryParams())) {
+ $data = $this->request->getQueryParams();
+
+ if(isset($data['search'])) {
+ $data = $data['search'];
+ $conditions = [
+ 'OR' => [
+ 'Users.id' => (int)$data,
+ 'Users.name LIKE' => '%' . $data . '%',
+ 'Users.email LIKE' => '%' . $data . '%',
+ ],
+ ];
+ $query = $query->where([$conditions]);
+ $search = $data;
+ }
+ }
+ }
+
+ $users = $query->toArray();
+ $this->set(compact('users', 'search'));
+
+ if($this->getRequest()->is('htmx')) {
+ $this->viewBuilder()->disableAutoLayout();
+
+ // we will only render the usersTable viewblock
+ $this->Htmx->setBlock('usersTable');
+ }
+}
+```
+
+
+
## License
Licensed under [The MIT License][mit].
diff --git a/src/Controller/Component/HtmxComponent.php b/src/Controller/Component/HtmxComponent.php
index 3f430a6..42a24a9 100644
--- a/src/Controller/Component/HtmxComponent.php
+++ b/src/Controller/Component/HtmxComponent.php
@@ -18,6 +18,13 @@ class HtmxComponent extends Component
*/
protected array $_defaultConfig = [];
+ /**
+ * The name of the block.
+ *
+ * @var string|null
+ */
+ protected ?string $block = null;
+
/**
* List of triggers to use on request
*
@@ -39,6 +46,19 @@ class HtmxComponent extends Component
*/
private array $triggersAfterSwap = [];
+ /**
+ * Get the callbacks this class is interested in.
+ *
+ * @return array
+ */
+ public function implementedEvents(): array
+ {
+ return [
+ 'View.beforeRender' => 'beforeRender',
+ 'View.afterRender' => 'afterRender',
+ ];
+ }
+
/**
* Initialize properties.
*
@@ -54,13 +74,28 @@ public function initialize(array $config): void
*
* @return void
*/
- public function beforeRender(): void
+ public function beforeRender($event): void
{
if ($this->getController()->getRequest()->is('htmx')) {
$this->prepare();
}
}
+ /**
+ * afterRender callback.
+ *
+ * If setBlock is used this will render the set block if it exists
+ *
+ * @return void
+ */
+ public function afterRender($event)
+ {
+ if (!empty($this->block) && $event->getSubject()->exists($this->block)) {
+ $block = $event->getSubject()->fetch($this->block);
+ $event->getSubject()->assign('content', $block);
+ }
+ }
+
/**
* The current URL of the browser when the htmx request was made.
*
@@ -289,7 +324,7 @@ public function clientRefresh(): ?Response
* @param array $headers The headers that will be set
* @return \Cake\Http\Response|null
*/
- public function stopPolling($content = '', array $headers = []): ?Response
+ public function stopPolling(string $content = '', array $headers = []): ?Response
{
$response = $this->getController()->getResponse();
@@ -322,4 +357,26 @@ private function encodeTriggers(array $triggers): string
return implode(',', array_keys($triggers));
}
+
+ /**
+ * Set a specific block to render
+ *
+ * @param string|null $block Name of the block
+ */
+ public function setBlock(?string $block): static
+ {
+ $this->block = $block;
+
+ return $this;
+ }
+
+ /**
+ * Get the block that will be rendered
+ *
+ * @return string|null
+ */
+ public function getBlock(): ?string
+ {
+ return $this->block;
+ }
}