Basics · Events
Bubbling and defaults
An element event is dispatched from the tree root down to the target, then
handlers run from the deepest element upward — this is bubbling. When a
button sits inside a clickable row, clicking the button runs the button’s
handler and then the row’s. Here markDone and selectRow both fire, and
because the row runs last it wins, so the status ends up saying the wrong
thing.
evt.StopPropagation() stops the event before it reaches handlers higher up
the path. Call it in the inner handler and the row never sees the click.
There is a second control, evt.PreventDefault(), which suppresses the
built-in action that runs after dispatch — the runtime activating a
focused button on Enter, typing a key into a focused input, moving focus on
Tab. Those defaults are why the Done button already responds to Enter with
no extra wiring: a focused button plus a click handler means Enter
synthesises a click. PreventDefault cancels whichever default would apply.
Your turn
Make the Done button own its click. Give markDone the event and stop the
click bubbling to the row:
func markDone(evt *sumi.DOMEvent) {
evt.StopPropagation()
status.Set("Marked done")
}
Press Run and click Done — the status now stays on “Marked done” instead of being overwritten by the row.