Edit Row

A table where any single row flips into an edit form in place. The server tracks one EditingID; the row whose ID matches renders inputs, every other row stays read-only. Each Edit/Save button carries its row ID in the button value, so the handler knows which record to act on.

Edit Row

NameEmail
Joe Smith joe@smith.org
Angie MacDowell angie@macdowell.org
Fuqua Tarkenton fuqua@tarkenton.org
Kim Yee kim@yee.org

Template

{{if eq $.EditingID .ID}} chooses the edit form vs the read-only cells per row.

{{define "content"}}
<article>
    <h3>Edit Row</h3>
    <table>
        <thead><tr><th>Name</th><th>Email</th><th></th></tr></thead>
        <tbody>
        {{range .Contacts}}
        <tr data-key="{{.ID}}">
            {{if eq $.EditingID .ID}}
            <td colspan="3">
                <form method="POST" class="inline">
                    <fieldset role="group">
                        <input name="name" value="{{.Name}}" aria-label="Name">
                        <input name="email" value="{{.Email}}" aria-label="Email">
                        <button name="save" value="{{.ID}}" class="compact">Save</button>
                        <button name="cancel" class="compact secondary">Cancel</button>
                    </fieldset>
                </form>
            </td>
            {{else}}
            <td>{{.Name}}</td>
            <td>{{.Email}}</td>
            <td>
                <form method="POST" class="inline">
                    <button name="edit" value="{{.ID}}" class="compact secondary outline">Edit</button>
                </form>
            </td>
            {{end}}
        </tr>
        {{end}}
        </tbody>
    </table>
</article>
{{end}}

edit-row.tmpl

Handler & state

Edit records which row is open (value = row ID); Save writes the fields back to that contact and clears EditingID.

type EditRowController struct{}

func (c *EditRowController) Edit(state EditRowState, ctx *livetemplate.Context) (EditRowState, error) {
	// Edit/Save buttons send their ID via `value` attribute — see
	// docs/references/progressive-complexity-reference.md.
	state.EditingID = ctx.GetString("value")
	return state, nil
}

func (c *EditRowController) Save(state EditRowState, ctx *livetemplate.Context) (EditRowState, error) {
	id := ctx.GetString("value")
	for i, contact := range state.Contacts {
		if contact.ID == id {
			state.Contacts[i].Name = ctx.GetString("name")
			state.Contacts[i].Email = ctx.GetString("email")
			break
		}
	}
	state.EditingID = ""
	return state, nil
}

func (c *EditRowController) Cancel(state EditRowState, ctx *livetemplate.Context) (EditRowState, error) {
	state.EditingID = ""
	return state, nil
}

func editRowHandler() http.Handler {
	tmpl := newLayoutTmpl("templates/layout.tmpl", "templates/forms/edit-row.tmpl")
	return tmpl.Handle(&EditRowController{}, livetemplate.AsState(&EditRowState{
		Title:    "Edit Row",
		Category: "Forms & Editing",
		Contacts: sampleContacts(),
	}))
}

handlers_forms.go:49-84

type EditRowState struct {
	Title     string
	Category  string
	Contacts  []Contact
	EditingID string
}

state_forms.go:18-24

When to use

For a single standalone record, Click to Edit is the simpler shape.

source: livetemplate/docs · path: examples/patterns/templates/forms/edit-row.tmpl