Skip to content

Commit 8f95af2

Browse files
authored
feat: add refresh flag to navigation event (#15324)
Add the isRefreshEvent to BeforeEnterEvent and AfterNavigationEvent to be make it possible to distinguish if the event is for a refresh of a preserve on refresh view. Fixes #14999
1 parent 3840a6f commit 8f95af2

File tree

5 files changed

+112
-1
lines changed

5 files changed

+112
-1
lines changed

flow-server/src/main/java/com/vaadin/flow/router/AfterNavigationEvent.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,13 @@ public List<HasElement> getActiveChain() {
7373
public Router getSource() {
7474
return (Router) super.getSource();
7575
}
76+
77+
/**
78+
* Check if event is for a refresh of a preserveOnRefresh view.
79+
*
80+
* @return true if refresh of a preserve on refresh view
81+
*/
82+
public boolean isRefreshEvent() {
83+
return event.getTrigger().equals(NavigationTrigger.REFRESH);
84+
}
7685
}

flow-server/src/main/java/com/vaadin/flow/router/BeforeEnterEvent.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,4 +111,13 @@ public BeforeEnterEvent(Router router, NavigationTrigger trigger,
111111
super(router, trigger, location, navigationTarget, parameters, ui,
112112
layouts);
113113
}
114+
115+
/**
116+
* Check if event is for a refresh of a preserveOnRefresh view.
117+
*
118+
* @return true if refresh of a preserve on refresh view
119+
*/
120+
public boolean isRefreshEvent() {
121+
return getTrigger().equals(NavigationTrigger.REFRESH);
122+
}
114123
}

flow-server/src/main/java/com/vaadin/flow/router/NavigationTrigger.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,10 @@ public enum NavigationTrigger {
6363
*
6464
* @see com.vaadin.flow.component.internal.JavaScriptBootstrapUI
6565
*/
66-
CLIENT_SIDE
66+
CLIENT_SIDE,
67+
68+
/**
69+
* Navigation is for a reload event on a preserveOnRefresh route.
70+
*/
71+
REFRESH
6772
}

flow-server/src/main/java/com/vaadin/flow/router/internal/AbstractNavigationStateRenderer.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,13 @@ public int handle(NavigationEvent event) {
189189
clearAllPreservedChains(ui);
190190
}
191191

192+
// Set navigationTrigger to RELOAD if this is a refresh of a preserve
193+
// view.
194+
if (preserveOnRefreshTarget && !chain.isEmpty()) {
195+
event = new NavigationEvent(event.getSource(), event.getLocation(),
196+
event.getUI(), NavigationTrigger.REFRESH);
197+
}
198+
192199
// If the navigation is postponed, using BeforeLeaveEvent#postpone,
193200
// pushing history state shouldn't be done. So, it's done here to make
194201
// sure that when history state is pushed the navigation is not

flow-server/src/test/java/com/vaadin/flow/router/internal/NavigationStateRendererTest.java

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@
4343
import com.vaadin.flow.component.page.Page;
4444
import com.vaadin.flow.component.page.PendingJavaScriptResult;
4545
import com.vaadin.flow.dom.Element;
46+
import com.vaadin.flow.router.AfterNavigationEvent;
47+
import com.vaadin.flow.router.AfterNavigationObserver;
48+
import com.vaadin.flow.router.BeforeEnterEvent;
49+
import com.vaadin.flow.router.BeforeEnterObserver;
50+
import com.vaadin.flow.router.BeforeLeaveEvent;
4651
import com.vaadin.flow.router.Location;
4752
import com.vaadin.flow.router.NavigationEvent;
4853
import com.vaadin.flow.router.NavigationState;
@@ -82,6 +87,29 @@ private static class PreservedView extends Text {
8287
}
8388
}
8489

90+
@Route(value = "preserved")
91+
@PreserveOnRefresh
92+
private static class PreservedEventView extends Text
93+
implements BeforeEnterObserver, AfterNavigationObserver {
94+
static boolean refreshBeforeEnter;
95+
static boolean refreshAfterNavigation;
96+
97+
PreservedEventView() {
98+
super("");
99+
}
100+
101+
@Override
102+
public void beforeEnter(BeforeEnterEvent event) {
103+
refreshBeforeEnter = event.isRefreshEvent();
104+
}
105+
106+
@Override
107+
public void afterNavigation(AfterNavigationEvent event) {
108+
refreshAfterNavigation = event.isRefreshEvent();
109+
110+
}
111+
}
112+
85113
@Route(value = "regular")
86114
private static class RegularView extends Text {
87115
RegularView() {
@@ -324,6 +352,59 @@ public void handle_preserveOnRefreshAndWindowNameKnown_componentIsCachedRetrieve
324352
session, new Location("preserved")));
325353
}
326354

355+
@Test
356+
public void handle_preserveOnRefresh_refreshIsFlaggedInEvent() {
357+
// given a service with instantiator
358+
MockVaadinServletService service = createMockServiceWithInstantiator();
359+
360+
// given a locked session
361+
MockVaadinSession session = new AlwaysLockedVaadinSession(service);
362+
session.setConfiguration(new MockDeploymentConfiguration());
363+
364+
// given a UI that contain a window name ROOT.123
365+
MockUI ui = new MockUI(session);
366+
ExtendedClientDetails details = Mockito
367+
.mock(ExtendedClientDetails.class);
368+
Mockito.when(details.getWindowName()).thenReturn("ROOT.123");
369+
ui.getInternals().setExtendedClientDetails(details);
370+
371+
// given a NavigationStateRenderer mapping to PreservedEventView
372+
NavigationStateRenderer renderer = new NavigationStateRenderer(
373+
navigationStateFromTarget(PreservedEventView.class));
374+
375+
// when a navigation event reaches the renderer
376+
renderer.handle(new NavigationEvent(new Router(new TestRouteRegistry()),
377+
new Location("preserved"), ui, NavigationTrigger.PAGE_LOAD));
378+
379+
// then the session has a cached record of the view
380+
Assert.assertTrue("Session expected to have cached view",
381+
AbstractNavigationStateRenderer.getPreservedChain(session,
382+
"ROOT.123", new Location("preserved")).isPresent());
383+
384+
// given the recently instantiated view
385+
final PreservedEventView view = (PreservedEventView) ui.getInternals()
386+
.getActiveRouterTargetsChain().get(0);
387+
Assert.assertFalse(
388+
"Initial view load should not be a refresh for before",
389+
view.refreshBeforeEnter);
390+
Assert.assertFalse(
391+
"Initial view load should not be a refresh for after",
392+
view.refreshAfterNavigation);
393+
394+
// when another navigation targets the same location
395+
renderer.handle(new NavigationEvent(new Router(new TestRouteRegistry()),
396+
new Location("preserved"), ui, NavigationTrigger.PAGE_LOAD));
397+
398+
// then the same view is routed to
399+
Assert.assertEquals("Expected same view", view,
400+
ui.getInternals().getActiveRouterTargetsChain().get(0));
401+
402+
Assert.assertTrue("Reload should be flagged for before",
403+
view.refreshBeforeEnter);
404+
Assert.assertTrue("Reload should be flagged for after",
405+
view.refreshAfterNavigation);
406+
}
407+
327408
@Test
328409
public void handle_preserveOnRefresh_otherUIChildrenAreMoved() {
329410
// given a service with instantiator

0 commit comments

Comments
 (0)