mirror of
https://github.com/bigskysoftware/htmx.git
synced 2025-09-30 14:31:47 +00:00
Merge branch 'master' into dev
This commit is contained in:
commit
4f2c3a53c1
@ -112,6 +112,8 @@ For added security, you can load the script using [Subresource Integrity (SRI)](
|
||||
<script src="https://unpkg.com/htmx.org@1.7.0" integrity="TODO: REGEN" crossorigin="anonymous"></script>
|
||||
```
|
||||
|
||||
If you are migrating to htmx from intercooler.js, please see the [migration guide here](/migration-guide).
|
||||
|
||||
## <a name="ajax"></a> [AJAX](#ajax)
|
||||
|
||||
The core of htmx is a set of attributes that allow you to issue AJAX requests directly from HTML:
|
||||
|
@ -20,6 +20,7 @@ You can copy and paste them and then adjust them for your needs.
|
||||
| [Bulk Update](/examples/bulk-update) | Demonstrates bulk updating of multiple rows of data
|
||||
| [Click To Load](/examples/click-to-load) | Demonstrates clicking to load more rows in a table
|
||||
| [Delete Row](/examples/delete-row) | Demonstrates row deletion in a table
|
||||
| [Edit Row](/examples/edit-row) | Demonstrates how to edit rows in a table
|
||||
| [Lazy Loading](/examples/lazy-load) | Demonstrates how to lazy load content
|
||||
| [Inline Validation](/examples/inline-validation) | Demonstrates how to do inline field validation
|
||||
| [Infinite Scroll](/examples/infinite-scroll) | Demonstrates infinite scrolling of a page
|
||||
|
215
www/examples/edit-row.md
Normal file
215
www/examples/edit-row.md
Normal file
@ -0,0 +1,215 @@
|
||||
---
|
||||
layout: demo_layout.njk
|
||||
---
|
||||
|
||||
## Edit Row
|
||||
|
||||
This example shows how to implement editable rows. First let's look at the table body:
|
||||
|
||||
```html
|
||||
<table class="table delete-row-example">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Email</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody hx-target="closest tr" hx-swap="outerHTML">
|
||||
...
|
||||
</tbody>
|
||||
</table>
|
||||
```
|
||||
|
||||
This will tell the requests from within the table to target the closest enclosing row that the request is triggered
|
||||
on and to replace the entire row.
|
||||
|
||||
Here is the HTML for a row:
|
||||
|
||||
```html
|
||||
<tr>
|
||||
<td>${contact.name}</td>
|
||||
<td>${contact.email}</td>
|
||||
<td>
|
||||
<button class="btn btn-danger"
|
||||
hx-get="/contact/${contact.id}/edit"
|
||||
hx-trigger="edit"
|
||||
_="on click
|
||||
if .editing is not empty
|
||||
Swal.fire({title: 'Already Editing',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Yep, Edit This Row!',
|
||||
text:'Hey! You are already editing a row! Do you want to cancel that edit and continue?'})
|
||||
if the result's isConfirmed is false
|
||||
halt
|
||||
end
|
||||
send cancel to .editing
|
||||
end
|
||||
trigger edit">
|
||||
Edit
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
```
|
||||
|
||||
Here we are getting a bit fancy and only allowing one row at a time to be edited, using [hyperscript](http://hyperscript.org).
|
||||
We check to see if there is a row with the `.editing` class on it and confirm that the user wants to edit this row
|
||||
and dismiss the other one. If so, we send a cancel event to the other row so it will issue a request to go back to
|
||||
its initial state.
|
||||
|
||||
We then trigger the `edit` event on the current element, which triggers the htmx request to get the editable version
|
||||
of the row.
|
||||
|
||||
Note that if you didn't care if a user was editing multiple rows, you could omit the hyperscript and custom `hx-trigger`,
|
||||
and just let the normal click handling work with htmx. You could also implement mutual exclusivity by simply targeting the
|
||||
entire table when the Edit button was clicked. Here we wanted to show how to integrate htmx and hyperscript to solve
|
||||
the problem and narrow down the server interactions a bit, plus we get to use a nice SweetAlert confirm dialog.
|
||||
|
||||
Finally, here is what the row looks like when the data is being edited:
|
||||
|
||||
```html
|
||||
<tr hx-trigger='cancel' class='editing' hx-get="/contact/${contact.id}">
|
||||
<td><input name='name' value='${contact.name}'</td>
|
||||
<td><input name='email' value='${contact.email}'</td>
|
||||
<td>
|
||||
<button class="btn btn-danger" hx-get="/contact/${contact.id}">
|
||||
Cancel
|
||||
</button>
|
||||
<button class="btn btn-danger" hx-put="/contact/${contact.id}" hx-include="closest tr">
|
||||
Save
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
```
|
||||
|
||||
Here we have a few things going on: First off the row itself can respond to the `cancel` event, which will bring
|
||||
back the read-only version of the row. This is used by the hyperscript above. There is a cancel button that allows
|
||||
cancelling the current edit. Finally, there is a save button that issues a `PUT` to update the contact. Note that
|
||||
there is an [`hx-include`](attributes/hx-include) that includes all the inputs in the closest row. Tables rows are
|
||||
notoriously difficult to use with forms due to HTML constraints (you can't put a `form` directly inside a `tr`) so
|
||||
this makes things a bit nicer to deal with.
|
||||
|
||||
{% include demo_ui.html.liquid %}
|
||||
|
||||
<script src="//cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
<script>
|
||||
//=========================================================================
|
||||
// Fake Server Side Code
|
||||
//=========================================================================
|
||||
|
||||
// data
|
||||
var contacts = [
|
||||
{
|
||||
name: "Joe Smith",
|
||||
email: "joe@smith.org",
|
||||
status: "Active",
|
||||
id: 0
|
||||
},
|
||||
{
|
||||
name: "Angie MacDowell",
|
||||
email: "angie@macdowell.org",
|
||||
status: "Active",
|
||||
id: 1
|
||||
},
|
||||
{
|
||||
name: "Fuqua Tarkenton",
|
||||
email: "fuqua@tarkenton.org",
|
||||
status: "Active",
|
||||
id: 2
|
||||
},
|
||||
{
|
||||
name: "Kim Yee",
|
||||
email: "kim@yee.org",
|
||||
status: "Inactive",
|
||||
id: 3
|
||||
},
|
||||
];
|
||||
|
||||
// routes
|
||||
init("/demo", function(request, params){
|
||||
return tableTemplate(contacts);
|
||||
});
|
||||
|
||||
onGet(/\/contact\/\d+/, function(request, params){
|
||||
var id = parseInt(request.url.split("/")[2]); // get the contact
|
||||
var contact = contacts[id];
|
||||
console.log(request, id, contact)
|
||||
if(request.url.endsWith("/edit")) {
|
||||
return editTemplate(contacts[id])
|
||||
} else {
|
||||
return rowTemplate(contacts[id])
|
||||
}
|
||||
});
|
||||
|
||||
onPut(/\/contact\/\d+/, function(request, params){
|
||||
var id = parseInt("/contact/0/edit".split("/")[2]); // get the contact
|
||||
contact = contacts[id]
|
||||
contact.name = params['name'];
|
||||
contact.email = params['email'];
|
||||
return rowTemplate(contact);
|
||||
});
|
||||
|
||||
// templates
|
||||
function rowTemplate(contact) {
|
||||
return `<tr>
|
||||
<td>${contact.name}</td>
|
||||
<td>${contact.email}</td>
|
||||
<td>
|
||||
<button class="btn btn-danger"
|
||||
hx-get="/contact/${contact.id}/edit"
|
||||
hx-trigger="edit"
|
||||
_="on click
|
||||
if .editing is not empty
|
||||
Swal.fire({title: 'Already Editing',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Yep, Edit This Row!',
|
||||
text:'Hey! You are already editing a row! Do you want to cancel that edit and continue?'})
|
||||
if the result's isConfirmed is false
|
||||
halt
|
||||
end
|
||||
send cancel to .editing
|
||||
end
|
||||
trigger edit">
|
||||
Edit
|
||||
</button>
|
||||
</td>
|
||||
</tr>`;
|
||||
}
|
||||
|
||||
function editTemplate(contact) {
|
||||
return `<tr hx-trigger='cancel' class='editing' hx-get="/contact/${contact.id}">
|
||||
<td><input name='name' value='${contact.name}'</td>
|
||||
<td><input name='email' value='${contact.email}'</td>
|
||||
<td>
|
||||
<button class="btn btn-danger" hx-get="/contact/${contact.id}">
|
||||
Cancel
|
||||
</button>
|
||||
<button class="btn btn-danger" hx-put="/contact/${contact.id}" hx-include="closest tr">
|
||||
Save
|
||||
</button>
|
||||
</td>
|
||||
</tr>`;
|
||||
}
|
||||
|
||||
function tableTemplate(contacts) {
|
||||
var rows = "";
|
||||
|
||||
for (var i = 0; i < contacts.length; i++) {
|
||||
rows += rowTemplate(contacts[i], i, "");
|
||||
}
|
||||
|
||||
return `
|
||||
<table class="table delete-row-example">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Email</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody hx-target="closest tr" hx-swap="outerHTML">
|
||||
${rows}
|
||||
</tbody>
|
||||
</table>`;
|
||||
}
|
||||
</script>
|
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user