SSR / Pages that work without JavaScript
The address is the state a GET carries
Mirror.url keeps fields of the Model in the address, and its reduce
reads them back, which is all a server needs to render the page a GET names:
export const SearchInUrl = Mirror.url(App, {
name: 'search',
fields: [App.model.query, App.model.tldFilter, App.model.availabilityFilter, App.model.sortOrder, App.model.from],
keys: {
query: { key: 'q', history: 'replace' },
tldFilter: { key: 'tld', history: 'replace' },
availabilityFilter: { key: 'availability', history: 'replace' },
sortOrder: { key: 'sort', history: 'replace' },
from: { history: 'replace' },
},
})
export const init = (url: Url) => start(SearchInUrl.reduce(empty, url))The search form is then a GET of /. Its text input is named q, and the
filters' plain selects join it with the form attribute, wherever they stand
in the page, so Enter in the box and Apply beside the filters send the same
query. With scripts, OnSubmit answers Enter and nothing is sent.
rh.form([h.Id('domain-search-form'), h.Method('get'), h.Action('/'), h.OnSubmit(Message.SubmittedSearch())], [
rh.input([h.Name('q'), h.Value(model.query), rh.OnInput(Message.UpdatedSearch)]),
])
h.select([h.Name('sort'), h.AriaLabel('Sort results'), h.Attribute('form', 'domain-search-form')], options)Give a GET form its method, Method('get'): with a server fallback, a form
rh builds with no Method is written to post its Message, and one with a
Method is left as the view draws it.
A link to another state of the page is SearchInUrl.href(model, { from: 13 },
'/'): the address with the mirrored keys patched, defaults left out. Give
it the base, so the server and the browser write the same link.
Mirroring the filters changes the scripted page too: choosing one now replaces the address, as the search text does. That is what makes a page reached without scripts the same page.