-
Notifications
You must be signed in to change notification settings - Fork 10.3k
Added additional boolean parameter "replace" to NavigationManager.NavigateTo #25752
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
46ef61b
cccf07e
b9a7c18
dd46f13
6a7fa63
6c23d72
9fb181c
4f3e72b
67adfa6
6c12545
50df74c
c2999fe
015b7ee
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
using System; | ||
|
||
namespace Microsoft.AspNetCore.Components | ||
{ | ||
/// <summary> | ||
/// Additional options for navigating to another URI | ||
/// </summary> | ||
[Flags] | ||
public enum NavigationOptions | ||
{ | ||
/// <summary> | ||
/// Use default options | ||
/// </summary> | ||
None = 0, | ||
/// <summary> | ||
MariovanZeist marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// Bypasses client-side routing and forces the browser to load the new page from the server, whether or not the URI would normally be handled by the client-side router. | ||
/// </summary> | ||
ForceLoad = 1, | ||
/// <summary> | ||
/// Indicates that the current history entry should be replaced, instead of pushing the new uri onto the browser history stack. | ||
/// </summary> | ||
ReplaceHistoryEntry = 2 | ||
} | ||
} |
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -80,7 +80,11 @@ export function navigateTo(uri: string, forceLoad: boolean, replace: boolean = f | |||||||||||||||||||||||||||||||||||||
history.replaceState(null, '', temporaryUri); | ||||||||||||||||||||||||||||||||||||||
location.replace(uri); | ||||||||||||||||||||||||||||||||||||||
} else if (replace){ | ||||||||||||||||||||||||||||||||||||||
history.replaceState(null, '', absoluteUri) | ||||||||||||||||||||||||||||||||||||||
if (forceLoad) { | ||||||||||||||||||||||||||||||||||||||
location.replace(uri); | ||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||
history.replaceState(null, '', absoluteUri) | ||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This logic looks wrong to me. What happens if What I'd expect is: since this is an external navigation, the force param is irrelevant, and the What the logic appears to do is call Here's the full truth table I'd expect (ignoring the Force-loading the same URL you're already on special case):
Do you agree with this list? Could you check how it corresponds to the implementation? I think the only combination that's currently wrong is the one I mentioned at the top of this comment. I suspect that before this PR, the logic here was already wrong in that it didn't handle |
||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||
// It's either an external URL, or forceLoad is requested, so do a full page load | ||||||||||||||||||||||||||||||||||||||
location.href = uri; | ||||||||||||||||||||||||||||||||||||||
|
@@ -91,7 +95,7 @@ function performInternalNavigation(absoluteInternalHref: string, interceptedLink | |||||||||||||||||||||||||||||||||||||
// Since this was *not* triggered by a back/forward gesture (that goes through a different | ||||||||||||||||||||||||||||||||||||||
// code path starting with a popstate event), we don't want to preserve the current scroll | ||||||||||||||||||||||||||||||||||||||
// position, so reset it. | ||||||||||||||||||||||||||||||||||||||
// To avoid ugly flickering effects, we don't want to change the scroll position until the | ||||||||||||||||||||||||||||||||||||||
// To avoid ugly flickering effects, we don't want to change the scroll position until | ||||||||||||||||||||||||||||||||||||||
// we render the new page. As a best approximation, wait until the next batch. | ||||||||||||||||||||||||||||||||||||||
resetScrollAfterNextBatch(); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -407,6 +407,122 @@ public void CanNavigateProgrammaticallyWithForceLoad() | |||
}); | ||||
} | ||||
|
||||
[Fact] | ||||
public void CanNavigateProgrammaticallyValidateNoReplaceHistoryEntry() | ||||
{ | ||||
//This test checks if default navigation does not replace Browser history entries | ||||
SetUrlViaPushState("/"); | ||||
|
||||
var app = Browser.MountTestComponent<TestRouter>(); | ||||
var testSelector = Browser.WaitUntilTestSelectorReady(); | ||||
|
||||
app.FindElement(By.LinkText("TestHistory")).Click(); | ||||
|
||||
Browser.True(() => Browser.Url.EndsWith("/TestHistory", StringComparison.Ordinal)); | ||||
Browser.Equal("This is the test history page.", () => app.FindElement(By.Id("test-info")).Text); | ||||
|
||||
|
||||
//We navigate to the /Other page | ||||
//This will also test our new NavigatTo(string uri) overload (it should not replace the browser history) | ||||
app.FindElement(By.Id("do-other-navigation")).Click(); | ||||
Browser.True(() => Browser.Url.EndsWith("/Other", StringComparison.Ordinal)); | ||||
AssertHighlightedLinks("Other", "Other with base-relative URL (matches all)"); | ||||
|
||||
Browser.Navigate().Back(); | ||||
//After we press back, we should end up at the "/TestHistory" page so we know browser history has not been replaced | ||||
//If history would have been replaced we would have ended up at the "/" page | ||||
Browser.True(() => Browser.Url.EndsWith("/TestHistory", StringComparison.Ordinal)); | ||||
AssertHighlightedLinks("TestHistory"); | ||||
|
||||
//For completeness, we will test if the normal NavigateTo(string uri, bool forceLoad) overload will also NOT change the browsers history | ||||
//So we basically repeat what we have done above | ||||
app.FindElement(By.Id("do-other-navigation2")).Click(); | ||||
Browser.True(() => Browser.Url.EndsWith("/Other", StringComparison.Ordinal)); | ||||
AssertHighlightedLinks("Other", "Other with base-relative URL (matches all)"); | ||||
|
||||
Browser.Navigate().Back(); | ||||
Browser.True(() => Browser.Url.EndsWith("/TestHistory", StringComparison.Ordinal)); | ||||
AssertHighlightedLinks("TestHistory"); | ||||
|
||||
// Because this was client-side navigation, we didn't lose the state in the test selector | ||||
Assert.Equal(typeof(TestRouter).FullName, testSelector.SelectedOption.GetAttribute("value")); | ||||
|
||||
app.FindElement(By.Id("do-other-navigation-forced")).Click(); | ||||
Browser.True(() => Browser.Url.EndsWith("/Other", StringComparison.Ordinal)); | ||||
|
||||
//We check if we had a force load | ||||
Assert.Throws<StaleElementReferenceException>(() => | ||||
{ | ||||
testSelector.SelectedOption.GetAttribute("value"); | ||||
}); | ||||
|
||||
////But still we should be able to navigate back, and end up at the "/TestHistory" page | ||||
Browser.Navigate().Back(); | ||||
Browser.True(() => Browser.Url.EndsWith("/TestHistory", StringComparison.Ordinal)); | ||||
Browser.WaitUntilTestSelectorReady(); | ||||
} | ||||
|
||||
|
||||
Comment on lines
+464
to
+465
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||
[Fact] | ||||
public void CanNavigateProgrammaticallyWithReplaceHistoryEntry() | ||||
{ | ||||
SetUrlViaPushState("/"); | ||||
|
||||
var app = Browser.MountTestComponent<TestRouter>(); | ||||
var testSelector = Browser.WaitUntilTestSelectorReady(); | ||||
|
||||
app.FindElement(By.LinkText("TestHistory")).Click(); | ||||
|
||||
Browser.True(() => Browser.Url.EndsWith("/TestHistory", StringComparison.Ordinal)); | ||||
Browser.Equal("This is the test history page.", () => app.FindElement(By.Id("test-info")).Text); | ||||
|
||||
|
||||
//We navigate to the /Other page, with replacehistroyentry enabled | ||||
app.FindElement(By.Id("do-other-navigation-replacehistoryentry")).Click(); | ||||
Browser.True(() => Browser.Url.EndsWith("/Other", StringComparison.Ordinal)); | ||||
AssertHighlightedLinks("Other", "Other with base-relative URL (matches all)"); | ||||
|
||||
Browser.Navigate().Back(); | ||||
//After we press back, we should end up at the "/" page so we know browser history has been replaced | ||||
//If history would not have been replaced we would have ended up at the "/TestHistory" page | ||||
Browser.True(() => Browser.Url.EndsWith("/", StringComparison.Ordinal)); | ||||
AssertHighlightedLinks("Default (matches all)", "Default with base-relative URL (matches all)"); | ||||
|
||||
// Because this was all with client-side navigation, we didn't lose the state in the test selector | ||||
Assert.Equal(typeof(TestRouter).FullName, testSelector.SelectedOption.GetAttribute("value")); | ||||
} | ||||
|
||||
[Fact] | ||||
public void CanNavigateProgrammaticallyWithForceLoadAndReplaceHistoryEntry() | ||||
{ | ||||
SetUrlViaPushState("/"); | ||||
|
||||
var app = Browser.MountTestComponent<TestRouter>(); | ||||
var testSelector = Browser.WaitUntilTestSelectorReady(); | ||||
|
||||
app.FindElement(By.LinkText("TestHistory")).Click(); | ||||
|
||||
Browser.True(() => Browser.Url.EndsWith("/TestHistory", StringComparison.Ordinal)); | ||||
Browser.Equal("This is the test history page.", () => app.FindElement(By.Id("test-info")).Text); | ||||
|
||||
//We navigate to the /Other page, with replacehistroyentry and forceload enabled | ||||
app.FindElement(By.Id("do-other-navigation-forced-replacehistoryentry")).Click(); | ||||
Browser.True(() => Browser.Url.EndsWith("/Other", StringComparison.Ordinal)); | ||||
|
||||
//We check if we had a force load | ||||
Assert.Throws<StaleElementReferenceException>(() => | ||||
{ | ||||
testSelector.SelectedOption.GetAttribute("value"); | ||||
}); | ||||
|
||||
Browser.Navigate().Back(); | ||||
//After we press back, we should end up at the "/" page so we know browser history has been replaced | ||||
Browser.True(() => Browser.Url.EndsWith("/", StringComparison.Ordinal)); | ||||
Browser.WaitUntilTestSelectorReady(); | ||||
} | ||||
|
||||
|
||||
|
||||
[Fact] | ||||
public void ClickingAnchorWithNoHrefShouldNotNavigate() | ||||
{ | ||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
@page "/TestHistory" | ||
@inject NavigationManager NavigationManager | ||
|
||
<div id="test-info">This is the test history page.</div> | ||
|
||
<button id="do-other-navigation" @onclick=@(_ => NavigationManager.NavigateTo("Other"))> | ||
Programmatic navigation (new overload) | ||
</button> | ||
|
||
<button id="do-other-navigation2" @onclick=@(_ => NavigationManager.NavigateTo("Other", false))> | ||
Programmatic navigation | ||
</button> | ||
|
||
<button id="do-other-navigation-forced" @onclick=@(_ => NavigationManager.NavigateTo("Other", true))> | ||
Programmatic navigation with force-load | ||
</button> | ||
|
||
<button id="do-other-navigation-replacehistoryentry" @onclick=@(_ => NavigationManager.NavigateTo("Other", NavigationOptions.ReplaceHistoryEntry))> | ||
Programmatic navigation with history replace | ||
</button> | ||
|
||
<button id="do-other-navigation-forced-replacehistoryentry" @onclick=@(_ => NavigationManager.NavigateTo("Other", NavigationOptions.ReplaceHistoryEntry | NavigationOptions.ForceLoad))> | ||
Programmatic navigation with force-load and history replace | ||
</button> |
Uh oh!
There was an error while loading. Please reload this page.