fix(ui): render whole-page Handler dot as template data, not a tag#190
Merged
Conversation
ui.Handler documents that each request renders the named template with dot exposed through With.Dot, with no tag-eligibility restriction. Whole-page rendering went through Template.render, which tag-expands the dot; a primitive value such as a string was rejected with ErrIllegalTagType and ServeHTTP logged and discarded the error, yielding HTTP 200 with an empty body. Give pageTemplate its own JawsRender that looks up and executes the template directly, so the page dot is treated as ordinary html/template data and never as a JaWS tag. The page element cannot re-render itself (JawsUpdate is a no-op), so its tag registration was always inert; partial ui.Template values keep deriving tag identity from their dot. Wrap the ResponseWriter so ServeHTTP sends a 500 for a render failure that occurs before any output (for example a missing template) instead of a blank 200. Once bytes are committed the partial body is left as-is, matching the best-effort execution semantics documented on Template. Fixes #178
Add public-API regression tests for ui.Handler: a string dot and a struct dot render (the issue #178 repro), a missing template returns HTTP 500 with a logged error, an execute error after output keeps the partial 200 body, a partial ui.Template still rejects a string dot, and a tag-valued page dot still renders. Package coverage stays at 100% under -race.
Render each request through a fresh per-request *pageTemplate so the UI stays comparable as a map key regardless of the page dot. Ordinary html/template data such as a slice or map is not usable as a tag; a bare pageTemplate value carrying it in its Dot any field is not comparable at runtime and trips the comparability check in Request.NewElement, which panics under -race. This matches the pointer-UI convention used by the html widgets (for example *Div). Add a regression test rendering slice and map page dots (guarded with tag.NewErrNotComparable so it exercises the non-comparable path), and reword the handler tests to describe current behavior.
linkdata
marked this pull request as ready for review
July 20, 2026 18:54
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #178.
ui.Handler(jw, name, dot)documents that each request renders the named template withdotexposed throughWith.Dot, with no tag-eligibility restriction. In practice a primitivedotsuch as a string produced HTTP 200 with an empty body.Whole-page rendering flowed through
Template.render, which unconditionally tag-expandsDot. A string is rejected withtag.ErrIllegalTagType, sorenderreturned before writing anything andServeHTTPlogged-and-discarded the error.Changes
pageTemplategets its ownJawsRenderthat looks up and executes the template directly (reusingTemplate.lookup/Template.execute), bypassing tag expansion. The page element cannot re-render itself — itsJawsUpdateis a deliberate no-op — so deriving tag identity from the page dot was always inert. Partialui.Templatevalues are untouched and keep deriving tag identity from their dot.ServeHTTPwraps theResponseWriterin a small recorder; a failure before any output (e.g. a missing template) now returns a clean500instead of a blank200. Once bytes are committed the partial body is left as-is, matching the best-effort execution semantics documented onTemplate.Acceptance criteria
ui.Handleraccepts ordinaryhtml/templatedata, including strings.ui.Templatetag behavior.go test -race.Testing
go test -race ./lib/ui/andgo test -race ./...— passgo vet,gofmt -l,gofumpt -l,staticcheck ./lib/ui/— cleango test -cover ./lib/ui/— 100.0% of statements