Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 94 additions & 7 deletions flow-server/src/main/java/com/vaadin/flow/component/UI.java
Original file line number Diff line number Diff line change
Expand Up @@ -1053,6 +1053,11 @@ public Page getPage() {
* If the view change actually happens (e.g. the view itself doesn't cancel
* the navigation), all navigation listeners are notified and a reference of
* the new view is returned for additional configuration.
* <p>
* Navigating to the location that is already shown does nothing: the view
* is not re-instantiated and no navigation lifecycle events are fired. Use
* {@link #refreshCurrentRoute(boolean)} to rebuild the view that is
* currently shown.
*
* @param <T>
* the navigation target type
Expand All @@ -1064,9 +1069,14 @@ public Page getPage() {
* @throws NotFoundException
* in case there is no route defined for the given
* navigationTarget.
* @return the view instance, if navigation actually happened
* @return the requested view instance, if it is part of the active route
* chain after this call. When the navigation was skipped because
* that view was already shown, this is the existing instance; when
* the navigation was rerouted or forwarded elsewhere, the result is
* empty.
* @see #navigate(Class, Object)
* @see #navigate(Class, RouteParameters)
* @see #refreshCurrentRoute(boolean)
*/
public <T extends Component> Optional<T> navigate(
Class<T> navigationTarget) {
Expand Down Expand Up @@ -1100,6 +1110,11 @@ private <T extends Component> Optional<T> findCurrentNavigationTarget(
* If the view change actually happens (e.g. the view itself doesn't cancel
* the navigation), all navigation listeners are notified and a reference of
* the new view is returned for additional configuration.
* <p>
* Navigating to the location that is already shown does nothing: the view
* is not re-instantiated and no navigation lifecycle events are fired. Use
* {@link #refreshCurrentRoute(boolean)} to rebuild the view that is
* currently shown.
*
* @param navigationTarget
* navigation target to navigate to
Expand All @@ -1109,14 +1124,19 @@ private <T extends Component> Optional<T> findCurrentNavigationTarget(
* url parameter type
* @param <C>
* navigation target type
* @return the view instance, if navigation actually happened
* @return the requested view instance, if it is part of the active route
* chain after this call. When the navigation was skipped because
* that view was already shown, this is the existing instance; when
* the navigation was rerouted or forwarded elsewhere, the result is
* empty.
* @throws IllegalArgumentException
* if a {@code null} parameter is given while navigationTarget's
* parameter is not annotated with @OptionalParameter
* or @WildcardParameter.
* @throws NotFoundException
* in case there is no route defined for the given
* navigationTarget matching the parameters.
* @see #refreshCurrentRoute(boolean)
*/
@SuppressWarnings("unchecked")
public <T, C extends Component & HasUrlParameter<T>> Optional<C> navigate(
Expand All @@ -1140,14 +1160,23 @@ public <T, C extends Component & HasUrlParameter<T>> Optional<C> navigate(
* If the view change actually happens (e.g. the view itself doesn't cancel
* the navigation), all navigation listeners are notified and a reference of
* the new view is returned for additional configuration.
* <p>
* Navigating to the location that is already shown does nothing: the view
* is not re-instantiated and no navigation lifecycle events are fired. Use
* {@link #refreshCurrentRoute(boolean)} to rebuild the view that is
* currently shown.
*
* @param <T>
* the navigation target type
* @param navigationTarget
* navigation target to navigate to.
* @param parameters
* parameters to pass to view.
* @return the view instance, if navigation actually happened
* @return the requested view instance, if it is part of the active route
* chain after this call. When the navigation was skipped because
* that view was already shown, this is the existing instance; when
* the navigation was rerouted or forwarded elsewhere, the result is
* empty.
* @throws IllegalArgumentException
* if navigationTarget is a {@link HasUrlParameter} with a
* mandatory parameter, but parameters argument doesn't provide
Expand All @@ -1156,6 +1185,7 @@ public <T, C extends Component & HasUrlParameter<T>> Optional<C> navigate(
* in case there is no route defined for the given
* navigationTarget matching the parameters.
* @since 4.0
* @see #refreshCurrentRoute(boolean)
*/
public <T extends Component> Optional<T> navigate(Class<T> navigationTarget,
RouteParameters parameters) {
Expand All @@ -1179,14 +1209,23 @@ public <T extends Component> Optional<T> navigate(Class<T> navigationTarget,
* If the view change actually happens (e.g. the view itself doesn't cancel
* the navigation), all navigation listeners are notified and a reference of
* the new view is returned for additional configuration.
* <p>
* Navigating to the location that is already shown does nothing: the view
* is not re-instantiated and no navigation lifecycle events are fired. Use
* {@link #refreshCurrentRoute(boolean)} to rebuild the view that is
* currently shown.
*
* @param <T>
* the navigation target type
* @param navigationTarget
* navigation target to navigate to.
* @param parameters
* parameters to pass to view.
* @return the view instance, if navigation actually happened
* @return the requested view instance, if it is part of the active route
* chain after this call. When the navigation was skipped because
* that view was already shown, this is the existing instance; when
* the navigation was rerouted or forwarded elsewhere, the result is
* empty.
* @throws IllegalArgumentException
* if navigationTarget is a {@link HasUrlParameter} with a
* mandatory parameter, but parameters argument doesn't provide
Expand All @@ -1195,6 +1234,7 @@ public <T extends Component> Optional<T> navigate(Class<T> navigationTarget,
* in case there is no route defined for the given
* navigationTarget matching the parameters.
* @since 24.1.1
* @see #refreshCurrentRoute(boolean)
*/
public <T extends Component> Optional<T> navigate(Class<T> navigationTarget,
RouteParam... parameters) {
Expand All @@ -1216,6 +1256,11 @@ public <T extends Component> Optional<T> navigate(Class<T> navigationTarget,
* If the view change actually happens (e.g. the view itself doesn't cancel
* the navigation), all navigation listeners are notified and a reference of
* the new view is returned for additional configuration.
* <p>
* Navigating to the location that is already shown does nothing: the view
* is not re-instantiated and no navigation lifecycle events are fired. Use
* {@link #refreshCurrentRoute(boolean)} to rebuild the view that is
* currently shown.
*
* @param navigationTarget
* navigation target to navigate to
Expand All @@ -1227,7 +1272,11 @@ public <T extends Component> Optional<T> navigate(Class<T> navigationTarget,
* url parameter type
* @param <C>
* navigation target type
* @return the view instance, if navigation actually happened
* @return the requested view instance, if it is part of the active route
* chain after this call. When the navigation was skipped because
* that view was already shown, this is the existing instance; when
* the navigation was rerouted or forwarded elsewhere, the result is
* empty.
* @throws IllegalArgumentException
* if a {@code null} parameter is given while navigationTarget's
* parameter is not annotated with @OptionalParameter
Expand All @@ -1236,6 +1285,7 @@ public <T extends Component> Optional<T> navigate(Class<T> navigationTarget,
* in case there is no route defined for the given
* navigationTarget matching the parameters.
* @since 23.2
* @see #refreshCurrentRoute(boolean)
*/
@SuppressWarnings("unchecked")
public <T, C extends Component & HasUrlParameter<T>> Optional<C> navigate(
Expand Down Expand Up @@ -1268,6 +1318,11 @@ public <T, C extends Component & HasUrlParameter<T>> Optional<C> navigate(
* If the view change actually happens (e.g. the view itself doesn't cancel
* the navigation), all navigation listeners are notified and a reference of
* the new view is returned for additional configuration.
* <p>
* Navigating to the location that is already shown does nothing: the view
* is not re-instantiated and no navigation lifecycle events are fired. Use
* {@link #refreshCurrentRoute(boolean)} to rebuild the view that is
* currently shown.
*
* @param navigationTarget
* navigation target to navigate to
Expand All @@ -1277,7 +1332,11 @@ public <T, C extends Component & HasUrlParameter<T>> Optional<C> navigate(
* additional query parameters to pass to view
* @param <C>
* navigation target type
* @return the view instance, if navigation actually happened
* @return the requested view instance, if it is part of the active route
* chain after this call. When the navigation was skipped because
* that view was already shown, this is the existing instance; when
* the navigation was rerouted or forwarded elsewhere, the result is
* empty.
* @throws IllegalArgumentException
* if a {@code null} parameter is given while navigationTarget's
* parameter is not annotated with @OptionalParameter
Expand All @@ -1286,6 +1345,7 @@ public <T, C extends Component & HasUrlParameter<T>> Optional<C> navigate(
* in case there is no route defined for the given
* navigationTarget matching the parameters.
* @since 24.1
* @see #refreshCurrentRoute(boolean)
*/
@SuppressWarnings("unchecked")
public <C extends Component> Optional<C> navigate(
Expand All @@ -1310,18 +1370,28 @@ public <C extends Component> Optional<C> navigate(
* If the view change actually happens (e.g. the view itself doesn't cancel
* the navigation), all navigation listeners are notified and a reference of
* the new view is returned for additional configuration.
* <p>
* Navigating to the location that is already shown does nothing: the view
* is not re-instantiated and no navigation lifecycle events are fired. Use
* {@link #refreshCurrentRoute(boolean)} to rebuild the view that is
* currently shown.
*
* @param navigationTarget
* navigation target to navigate to
* @param queryParameters
* additional query parameters to pass to view
* @param <T>
* navigation target type
* @return the view instance, if navigation actually happened
* @return the requested view instance, if it is part of the active route
* chain after this call. When the navigation was skipped because
* that view was already shown, this is the existing instance; when
* the navigation was rerouted or forwarded elsewhere, the result is
* empty.
* @throws NotFoundException
* in case there is no route defined for the given
* navigationTarget matching the parameters.
* @since 23.2
* @see #refreshCurrentRoute(boolean)
*/
@SuppressWarnings("unchecked")
public <T extends Component> Optional<T> navigate(
Expand Down Expand Up @@ -1351,9 +1421,15 @@ public <T extends Component> Optional<T> navigate(
* <p>
* Besides the navigation to the {@code location} this method also updates
* the browser location (and page history).
* <p>
* Navigating to the location that is already shown does nothing: the view
* is not re-instantiated and no navigation lifecycle events are fired. Use
* {@link #refreshCurrentRoute(boolean)} to rebuild the view that is
* currently shown.
*
* @see #navigate(String, QueryParameters)
* @see Router#navigate(UI, Location, NavigationTrigger)
* @see #refreshCurrentRoute(boolean)
*
* @param location
* the location to navigate to, not {@code null}
Expand All @@ -1371,9 +1447,15 @@ public void navigate(String location) {
* <p>
* Besides the navigation to the {@code location} this method also updates
* the browser location (and page history).
* <p>
* Navigating to the location that is already shown does nothing: the view
* is not re-instantiated and no navigation lifecycle events are fired. Use
* {@link #refreshCurrentRoute(boolean)} to rebuild the view that is
* currently shown.
*
* @see #navigate(String)
* @see Router#navigate(UI, Location, NavigationTrigger)
* @see #refreshCurrentRoute(boolean)
*
* @param locationString
* the location to navigate to, not {@code null}
Expand Down Expand Up @@ -1454,6 +1536,10 @@ public void navigate(String locationString,
* Re-navigates to the current route. Also re-instantiates the route target
* component, and optionally all layouts in the route chain.
* <p>
* This is the way to rebuild the view that is currently shown, since
* {@link #navigate(Class) navigating} to the location that is already shown
* does nothing.
* <p>
* In development mode, local signal field values are automatically
* transferred from the old component instance to the new one, preserving UI
* state across refreshes.
Expand All @@ -1462,6 +1548,7 @@ public void navigate(String locationString,
* {@code true} to refresh all layouts in the route chain,
* {@code false} to only refresh the route instance
* @since 24.4
* @see #navigate(Class)
*/
public void refreshCurrentRoute(boolean refreshRouteChain) {
getInternals().refreshCurrentRoute(refreshRouteChain);
Expand Down
24 changes: 24 additions & 0 deletions flow-server/src/test/java/com/vaadin/flow/component/UITest.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
Expand Down Expand Up @@ -444,6 +445,29 @@ public void locationAfterServerNavigation()
CoreMatchers.instanceOf(FooBarNavigationTarget.class));
}

@Test
public void navigateToShownView_notReinstantiated_shownInstanceReturned()
throws InvalidRouteConfigurationException {
UI ui = new UI();
initUI(ui, "", null);

FooBarNavigationTarget shownView = ui
.navigate(FooBarNavigationTarget.class).orElseThrow();

// Navigating to the location that is already shown does nothing, so
// the returned Optional holds the view that is already shown
FooBarNavigationTarget sameView = ui
.navigate(FooBarNavigationTarget.class).orElseThrow();

assertSame(shownView, sameView,
"Navigating to the shown view should not re-instantiate it");

ui.refreshCurrentRoute(false);

assertNotSame(shownView, ui.getCurrentView(),
"refreshCurrentRoute should re-instantiate the shown view");
}

@Test
@Disabled("Check what is the new Router.navigate for JavaScriptUI")
public void navigateWithParameters_delegateToRouter() {
Expand Down
Loading