mirror of
https://github.com/bigskysoftware/htmx.git
synced 2025-10-02 15:25:26 +00:00

* fix accesibility and keyboard navigation issues in examples * fix review comments * remove redundant aria attributes, remove redundant autofocus * rework progress bar demo's accesibility * rework tabs HATEOS example to be more ARIA compliant * rework tabs _hyperscript example to be ARIA compliant
164 lines
4.6 KiB
Markdown
164 lines
4.6 KiB
Markdown
+++
|
|
title = "Bulk Update"
|
|
template = "demo.html"
|
|
+++
|
|
|
|
This demo shows how to implement a common pattern where rows are selected and then bulk updated. This is
|
|
accomplished by putting a form around a table, with checkboxes in the table, and then including the checked
|
|
values in `PUT`'s to two different endpoints: `activate` and `deactivate`:
|
|
|
|
```html
|
|
<div hx-include="#checked-contacts" hx-target="#tbody">
|
|
<button class="btn" hx-put="/activate">Activate</button>
|
|
<button class="btn" hx-put="/deactivate">Deactivate</button>
|
|
</div>
|
|
|
|
<form id="checked-contacts">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th></th>
|
|
<th>Name</th>
|
|
<th>Email</th>
|
|
<th>Status</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="tbody">
|
|
<tr class="">
|
|
<td><input type='checkbox' name='ids' value='0'></td>
|
|
<td>Joe Smith</td>
|
|
<td>joe@smith.org</td>
|
|
<td>Active</td>
|
|
</tr>
|
|
...
|
|
</tbody>
|
|
</table>
|
|
</form>
|
|
```
|
|
|
|
The server will either activate or deactivate the checked users and then rerender the `tbody` tag with
|
|
updated rows. It will apply the class `activate` or `deactivate` to rows that have been mutated. This allows
|
|
us to use a bit of CSS to flash a color helping the user see what happened:
|
|
|
|
```css
|
|
.htmx-settling tr.deactivate td {
|
|
background: lightcoral;
|
|
}
|
|
.htmx-settling tr.activate td {
|
|
background: darkseagreen;
|
|
}
|
|
tr td {
|
|
transition: all 1.2s;
|
|
}
|
|
```
|
|
|
|
You can see a working example of this code below.
|
|
|
|
<style scoped="">
|
|
.htmx-settling tr.deactivate td {
|
|
background: lightcoral;
|
|
}
|
|
.htmx-settling tr.activate td {
|
|
background: darkseagreen;
|
|
}
|
|
tr td {
|
|
transition: all 1.2s;
|
|
}
|
|
</style>
|
|
|
|
{{ demoenv() }}
|
|
|
|
<script>
|
|
//=========================================================================
|
|
// Fake Server Side Code
|
|
//=========================================================================
|
|
|
|
// data
|
|
var dataStore = function(){
|
|
var data = [
|
|
{ name: "Joe Smith", email: "joe@smith.org", status: "Active" },
|
|
{ name: "Angie MacDowell", email: "angie@macdowell.org", status: "Active" },
|
|
{ name: "Fuqua Tarkenton", email: "fuqua@tarkenton.org", status: "Active" },
|
|
{ name: "Kim Yee", email: "kim@yee.org", status: "Inactive" }
|
|
];
|
|
return {
|
|
findContactById : function(id) {
|
|
return data[id];
|
|
},
|
|
allContacts : function() {
|
|
return data;
|
|
}
|
|
}
|
|
}()
|
|
|
|
function getIds(params) {
|
|
if(params['ids']) {
|
|
if(Array.isArray(params['ids'])) {
|
|
return params['ids'].map(x => parseInt(x))
|
|
} else {
|
|
return [parseInt(params['ids'])];
|
|
}
|
|
} else {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
// routes
|
|
init("/demo", function(request){
|
|
return displayUI(dataStore.allContacts());
|
|
});
|
|
|
|
onPut("/activate", function(request, params){
|
|
var ids = getIds(params);
|
|
for (var i = 0; i < ids.length; i++) {
|
|
dataStore.findContactById(ids[i])['status'] = 'Active';
|
|
}
|
|
return displayTable(ids, dataStore.allContacts(), 'activate');
|
|
});
|
|
|
|
onPut("/deactivate", function (req, params) {
|
|
var ids = getIds(params);
|
|
for (var i = 0; i < ids.length; i++) {
|
|
dataStore.findContactById(ids[i])['status'] = 'Inactive';
|
|
}
|
|
return displayTable(ids, dataStore.allContacts(), 'deactivate');
|
|
});
|
|
|
|
// templates
|
|
function displayUI(contacts) {
|
|
return `<h3>Select Rows And Activate Or Deactivate Below</h3>
|
|
<form id="checked-contacts">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th></th>
|
|
<th>Name</th>
|
|
<th>Email</th>
|
|
<th>Status</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="tbody">
|
|
${displayTable([], contacts, "")}
|
|
</tbody>
|
|
</table>
|
|
</form>
|
|
<br/>
|
|
<br/>
|
|
<div hx-include="#checked-contacts" hx-target="#tbody">
|
|
<button class="btn" hx-put="/activate">Activate</button>
|
|
<button class="btn" hx-put="/deactivate">Deactivate</button>
|
|
</div>`
|
|
}
|
|
|
|
function displayTable(ids, contacts, action) {
|
|
var txt = "";
|
|
for (var i = 0; i < contacts.length; i++) {
|
|
var c = contacts[i];
|
|
txt += `\n<tr class="${ids.includes(i) ? action : ""}">
|
|
<td><input type='checkbox' name='ids' value='${i}'></td><td>${c.name}</td><td>${c.email}</td><td>${c.status}</td>
|
|
</tr>`
|
|
}
|
|
return txt;
|
|
}
|
|
</script>
|