Skip to content

Browser refresh clears form values; underlying tension between page-instance preservation and singleton data freshness #456

@tkuhn

Description

@tkuhn

Symptom

On both production (https://nanodash.knowledgepixels.com) and locally, when a user partially fills a form (e.g. on /publish?template=...) and presses browser refresh (F5), the page reloads with all fields blank. The previously entered values are gone.

This used to work: refresh restored the partly-filled form.

History / root cause

There are two relevant commits:

  1. e03c61594 (PR #401, 2026-03-16) — fix: use ONE_PASS_RENDER so browser refresh creates fresh pages. This switched Wicket's render strategy from the default REDIRECT_TO_BUFFER to ONE_PASS_RENDER in WicketApplication.java. The commit message:

    With the default REDIRECT_TO_BUFFER strategy, Wicket added page instance info to the URL. Browser refresh then loaded the stored page (with its already-built component tree) instead of creating a new one, so updated data from singletons like Space was not reflected in the HTML. Switching to ONE_PASS_RENDER keeps URLs clean, so F5 always creates a new page instance that reads current data.

  2. 063c82c2 (PR #449, 2026-04-22) — refactor: drop formobj, use PageReference for preview Back. This removed the formobj session-stored form-map workaround that had been compensating for the lost state in PublishPage since 8d1f2c5a (2025-06-05).

So the chain is:

The underlying tension

ONE_PASS_RENDER was introduced to solve a real problem: pages held direct references to mutable singleton data (e.g. a Space object), so after the page was restored from the page store on F5, the HTML rendered from stale fields rather than reflecting current singleton state.

REDIRECT_TO_BUFFER and ONE_PASS_RENDER are opposite trade-offs of the same setting:

Strategy F5 behavior Form state on F5 Singleton data on F5
REDIRECT_TO_BUFFER (default) restore stored page preserved stale if held by reference
ONE_PASS_RENDER (current) build fresh page lost fresh

You cannot have both via the render-strategy knob alone.

Proposed solution

The Wicket-idiomatic fix is to leave the render strategy at the default REDIRECT_TO_BUFFER and stop holding live data references in the component tree. Use LoadableDetachableModel (LDM) for anything fetched from a singleton/registry.

An LDM serializes only the identifier (e.g. a space id) and detaches at the end of every request. On the next render it re-loads via load(). So even when Wicket restores a stored page tree on F5, anything wrapped in an LDM re-fetches from the singleton before rendering.

This gives us both:

  • F5 preserves the stored page instance → form state intact
  • LDMs re-fetch on each render → singleton data always fresh

Concrete pattern (e.g. for Space)

```java
IModel spaceModel = new LoadableDetachableModel() {
@OverRide protected Space load() {
return SpaceRepository.get().findById(spaceId); // only spaceId is serialized
}
};
```

Then pass spaceModel to components or use PropertyModel.of(spaceModel, \"label\"). Label, ListView, etc. all accept IModel natively.

Steps

  1. Fix the pages PR Instances sometimes get slow and eventually unresponsive after a while #401 was about. Change page fields from Space space / MaintainedResource resource to String id + an LDM. Replace direct space.getXxx() calls with PropertyModel.of(spaceModel, \"xxx\") or short helper LDMs.
    • page/SpacePage.java:53private final Space space field captures snapshot.
    • page/MaintainedResourcePage.java:41 — same pattern with MaintainedResource resource.
  2. Fix ExplorePage.java:129-133. Replace Model.of(\"back to \" + …findById(contextId).getLabel()) with an LDM that re-resolves the label.
  3. Fix HomePage.java:73. Replace the findById(...) snapshot passed to ViewList with an LDM if the home resource is editable mid-session.
  4. Remove the ONE_PASS_RENDER setting from WicketApplication.java:139.
  5. Verify by F5-testing. Other pages that hold singleton references (ResourcePartPage, SearchPage, DownloadRdfPage, UserPage, ChannelPage, ListPage, PreviewPage, ViewPage, SpaceListPage) are medium-risk — most hold data that is effectively immutable within a session. Convert any that show stale data in testing, following the same LDM pattern.

Wins of the revert

These form pages will immediately get F5-preserves-state behavior back:

  • PublishPage
  • GenPublishPage
  • All forms under page/connector/

Notes

  • This issue is independent of (but in the same neighborhood as) #271 (fixed in PR #455), which dealt with shared template-component models being overwritten by URL params.
  • The audit above lists only file:line references for the high-risk pages. A fuller list of medium-risk pages is available on request.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions