Skip to content

Commit cddf698

Browse files
authored
Fix for filters not working with pagination (#469)
Targets bug #437 Easy testing with the concurrent userSeeder
1 parent 62b1365 commit cddf698

File tree

7 files changed

+65
-52
lines changed

7 files changed

+65
-52
lines changed

docs/building_admin_modules/filters.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,11 @@ There are 4 parts that are needed to get a working, filterable list of resources
9595
The main route for your resource list page must support both GET and POST methods.
9696

9797
```php
98-
$routes->match(['get', 'post'], 'users', 'UserController::list', ['as' => 'user-list']);
98+
$routes->match(['GET', 'POST'], 'users', 'UserController::list', ['as' => 'user-list']);
9999
```
100100

101-
The controller should then choose between sending either a full HTML page for a GET request, or just
102-
sending back the table for POST requests. You might do it something like:
101+
The controller should then choose between sending either a full HTML page for a regular GET request,
102+
or just sending back the table for ajax requests issued via HTMX. You might do it something like:
103103

104104
```php
105105
public function list()
@@ -109,7 +109,7 @@ public function list()
109109
// Performs the actual filtering of the results.
110110
$userModel->filter($this->request->getPost('filters'));
111111

112-
$view = $this->request->getMethod() == 'post'
112+
$view = $this->request->hasHeader('HX-Request')
113113
? $this->viewPrefix .'_table'
114114
: $this->viewPrefix .'list';
115115

@@ -151,14 +151,17 @@ Here's how this is used for the list of users within Bonfire.
151151

152152
<div class="row">
153153
<!-- List Users -->
154-
<div class="col" id="user-list">
154+
<div class="col" id="content-list">
155155
<?= $this->include('Bonfire\Users\Views\_table') ?>
156156
</div>
157157

158158
<!-- Filters -->
159159
<div class="col-auto" x-show="filtered" x-transition.duration.240ms>
160-
<?= view_cell('Bonfire\Libraries\Cells\Filters::renderList', 'model=UserFilter target=#user-list') ?>
160+
<?= view_cell('Bonfire\Libraries\Cells\Filters::renderList 'model=UserFilter target=#content-list') ?>
161161
</div>
162162
</div>
163163
</div>
164164
```
165+
166+
Note that the id of the eleent that contains the included table should be with `id="content-list"` as it this `id` is
167+
the default target for content replacements by the pager and the filter.

src/Users/Controllers/UserController.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ public function list()
3939
/** @var UserFilter $userModel */
4040
$userModel = model(UserFilter::class);
4141

42-
$userModel->filter($this->request->getPost('filters'));
42+
$userModel->filter($this->request->getGet('filters'));
4343

44-
$view = $this->request->getMethod() === 'post'
44+
$view = $this->request->hasHeader('HX-Request')
4545
? $this->viewPrefix . '_table'
4646
: $this->viewPrefix . 'list';
4747

@@ -70,6 +70,8 @@ public function create()
7070
$groups = setting('AuthGroups.groups');
7171
asort($groups);
7272

73+
helper('form');
74+
7375
return $this->render($this->viewPrefix . 'form', [
7476
'groups' => $groups,
7577
]);

src/Users/Views/_table.php

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,29 @@
1-
<div class="table-responsive">
2-
<table class="table table-hover">
3-
<?= $this->include('_table_head') ?>
4-
<tbody>
5-
<?php if (isset($users) && count($users)) : ?>
6-
<?php foreach ($users as $user) : ?>
7-
<tr>
8-
<?php if (auth()->user()->can('users.delete')) : ?>
9-
<td>
10-
<input type="checkbox" name="selects[<?= $user->id ?>]" class="form-check">
11-
</td>
12-
<?php endif ?>
13-
<?= view('Bonfire\Users\Views\_row_info', ['user' => $user]) ?>
14-
</tr>
15-
<?php endforeach ?>
16-
<?php endif ?>
17-
</tbody>
18-
</table>
19-
</div>
1+
<form action="<?= site_url(ADMIN_AREA . '/users/delete-batch') ?>" method="post">
2+
<?= csrf_field() ?>
3+
<div class="table-responsive">
4+
<table class="table table-hover">
5+
<?= $this->include('_table_head') ?>
6+
<tbody>
7+
<?php if (isset($users) && count($users)) : ?>
8+
<?php foreach ($users as $user) : ?>
9+
<tr>
10+
<?php if (auth()->user()->can('users.delete')) : ?>
11+
<td>
12+
<input type="checkbox" name="selects[<?= $user->id ?>]" class="form-check">
13+
</td>
14+
<?php endif ?>
15+
<?= view('Bonfire\Users\Views\_row_info', ['user' => $user]) ?>
16+
</tr>
17+
<?php endforeach ?>
18+
<?php endif ?>
19+
</tbody>
20+
</table>
21+
</div>
2022

21-
<?php if (auth()->user()->can('users.delete')) : ?>
22-
<input type="submit" value="Delete Selected" class="btn btn-sm btn-outline-danger" />
23-
<?php endif ?>
23+
<?php if (auth()->user()->can('users.delete')) : ?>
24+
<input type="submit" value="Delete Selected" class="btn btn-sm btn-outline-danger" />
25+
<?php endif ?>
26+
</form>
2427

2528
<div class="text-center">
2629
<?= $pager->links('default', 'bonfire_full') ?>

src/Users/Views/list.php

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,13 @@
2020

2121
<div class="row">
2222
<!-- List Users -->
23-
<div class="col" id="user-list">
24-
<form action="<?= site_url(ADMIN_AREA . '/users/delete-batch') ?>" method="post">
25-
<?= csrf_field() ?>
26-
27-
<?= $this->include('Bonfire\Users\Views\_table') ?>
28-
</form>
23+
<div class="col" id="content-list">
24+
<?= $this->include('Bonfire\Users\Views\_table') ?>
2925
</div>
3026

3127
<!-- Filters -->
3228
<div class="col-auto" x-show="filtered" x-transition.duration.240ms>
33-
<?= view_cell('Bonfire\Core\Cells\Filters::renderList', 'model=UserFilter target=#user-list') ?>
29+
<?= view_cell('Bonfire\Core\Cells\Filters::renderList', 'model=UserFilter target=#content-list') ?>
3430
</div>
3531
</div>
3632
</div>

src/Views/_filter_list.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<section class="filters">
22
<?php if (isset($filters) && count($filters)): ?>
3-
<form action="<?= current_url() ?>" method="post"
4-
hx-post="<?= current_url() ?>"
3+
<form action="<?= current_url() ?>" method="get"
4+
hx-get="<?= current_url() ?>"
55
hx-trigger="change delay:400ms from:.filter-check"
66
hx-target="<?= $target ?>"
77
>

src/Views/_pager_full.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,36 +10,36 @@
1010

1111
<?php if ($pager->getPageCount() > 1) : ?>
1212
<nav aria-label="<?= lang('Pager.pageNavigation') ?>" class="d-flex justify-content-center">
13-
<ul class="pagination">
13+
<ul class="pagination" hx-target="#content-list">
1414
<?php if ($pager->hasPrevious()) : ?>
1515
<li class="page-item">
16-
<a href="<?= $pager->getFirst() ?>" aria-label="<?= lang('Pager.first') ?>" class="page-link">
16+
<a href="<?= $pager->getFirst() ?>" hx-get="<?= $pager->getFirst() ?>" aria-label="<?= lang('Pager.first') ?>" class="page-link">
1717
<span aria-hidden="true"><?= lang('Pager.first') ?></span>
1818
</a>
1919
</li>
2020
<li class="page-item">
21-
<a href="<?= $pager->getPrevious() ?>" aria-label="<?= lang('Pager.previous') ?>" class="page-link">
21+
<a href="<?= $pager->getPrevious() ?>" hx-get="<?= $pager->getPrevious() ?>" aria-label="<?= lang('Pager.previous') ?>" class="page-link">
2222
<span aria-hidden="true"><?= lang('Pager.previous') ?></span>
2323
</a>
2424
</li>
2525
<?php endif ?>
2626

2727
<?php foreach ($pager->links() as $link) : ?>
2828
<li class="page-item <?= $link['active'] ? 'active' : '' ?>">
29-
<a href="<?= $link['uri'] ?>" class="page-link">
29+
<a href="<?= $link['uri'] ?>" hx-get="<?= $link['uri'] ?>" class="page-link">
3030
<?= $link['title'] ?>
3131
</a>
3232
</li>
3333
<?php endforeach ?>
3434

3535
<?php if ($pager->hasNext()) : ?>
3636
<li class="page-item">
37-
<a href="<?= $pager->getNext() ?>" aria-label="<?= lang('Pager.next') ?>" class="page-link">
37+
<a href="<?= $pager->getNext() ?>" hx-get="<?= $pager->getNext() ?>" aria-label="<?= lang('Pager.next') ?>" class="page-link">
3838
<span aria-hidden="true"><?= lang('Pager.next') ?></span>
3939
</a>
4040
</li>
4141
<li class="page-item">
42-
<a href="<?= $pager->getLast() ?>" aria-label="<?= lang('Pager.last') ?>" class="page-link">
42+
<a href="<?= $pager->getLast() ?>" hx-get="<?= $pager->getLast() ?>" aria-label="<?= lang('Pager.last') ?>" class="page-link">
4343
<span aria-hidden="true"><?= lang('Pager.last') ?></span>
4444
</a>
4545
</li>

themes/Admin/js/admin.js

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,25 @@ function toggleSelectAll(checkbox) {
1313
}
1414
}
1515

16-
// Check if there is a .select-all element on the page
17-
const selectAllElement = document.querySelector('.select-all');
16+
// Function to attach the event listener
17+
function attachSelectAllListener() {
18+
const selectAllElement = document.querySelector('.select-all');
1819

19-
// Attach the event listener only if the element exists
20-
if (selectAllElement) {
21-
selectAllElement.addEventListener('click', function (e) {
22-
toggleSelectAll(e.target);
23-
});
20+
// Attach the event listener only if the element exists
21+
if (selectAllElement) {
22+
selectAllElement.addEventListener('click', function (e) {
23+
toggleSelectAll(e.target);
24+
});
25+
}
2426
}
2527

28+
// Initial attachment
29+
attachSelectAllListener();
30+
31+
// Re-attach the event listener after each htmx request
32+
document.body.addEventListener('htmx:afterSettle', function () {
33+
attachSelectAllListener();
34+
});
2635

2736
// function for recycler get requests issued directly from select box
2837
function sendRecyclerGetRequest(selectedValue) {

0 commit comments

Comments
 (0)