From 93127b39e824181d4f9b1a62b6fc8d10c481e2c8 Mon Sep 17 00:00:00 2001 From: Steve Sanderson <SteveSandersonMS@users.noreply.github.com> Date: Fri, 14 Dec 2018 17:05:45 +0000 Subject: [PATCH] Overload UriHelper to forceLoad the page (imported from Blazor PR 1154) (#4786) --- .../src/Services/UriHelper.ts | 5 ++-- .../Services/BrowserUriHelper.cs | 4 +-- .../Circuits/RemoteUriHelper.cs | 10 +++---- .../Services/IUriHelper.cs | 8 ++++++ .../Services/UriHelperBase.cs | 16 ++++++++++-- .../Tests/RoutingTest.cs | 26 ++++++++++++++++++- .../BasicTestApp/RouterTest/Links.cshtml | 6 ++++- 7 files changed, 60 insertions(+), 15 deletions(-) diff --git a/src/Components/src/Microsoft.AspNetCore.Components.Browser.JS/src/Services/UriHelper.ts b/src/Components/src/Microsoft.AspNetCore.Components.Browser.JS/src/Services/UriHelper.ts index 169916d8adc..d867adab0e7 100644 --- a/src/Components/src/Microsoft.AspNetCore.Components.Browser.JS/src/Services/UriHelper.ts +++ b/src/Components/src/Microsoft.AspNetCore.Components.Browser.JS/src/Services/UriHelper.ts @@ -41,9 +41,10 @@ function enableNavigationInterception(assemblyName: string, functionName: string window.addEventListener('popstate', handleInternalNavigation); } -export function navigateTo(uri: string) { +export function navigateTo(uri: string, forceLoad: boolean) { const absoluteUri = toAbsoluteUri(uri); - if (isWithinBaseUriSpace(absoluteUri)) { + + if (!forceLoad && isWithinBaseUriSpace(absoluteUri)) { performInternalNavigation(absoluteUri); } else { location.href = uri; diff --git a/src/Components/src/Microsoft.AspNetCore.Components.Browser/Services/BrowserUriHelper.cs b/src/Components/src/Microsoft.AspNetCore.Components.Browser/Services/BrowserUriHelper.cs index 8cd50f9c545..cd4337b4f81 100644 --- a/src/Components/src/Microsoft.AspNetCore.Components.Browser/Services/BrowserUriHelper.cs +++ b/src/Components/src/Microsoft.AspNetCore.Components.Browser/Services/BrowserUriHelper.cs @@ -47,14 +47,14 @@ namespace Microsoft.AspNetCore.Components.Browser.Services } /// <inheritdoc /> - protected override void NavigateToCore(string uri) + protected override void NavigateToCore(string uri, bool forceLoad) { if (uri == null) { throw new ArgumentNullException(nameof(uri)); } - ((IJSInProcessRuntime)JSRuntime.Current).Invoke<object>(Interop.NavigateTo, uri); + ((IJSInProcessRuntime)JSRuntime.Current).Invoke<object>(Interop.NavigateTo, uri, forceLoad); } /// <summary> diff --git a/src/Components/src/Microsoft.AspNetCore.Components.Server/Circuits/RemoteUriHelper.cs b/src/Components/src/Microsoft.AspNetCore.Components.Server/Circuits/RemoteUriHelper.cs index 9b7eaa7e844..85149fcf690 100644 --- a/src/Components/src/Microsoft.AspNetCore.Components.Server/Circuits/RemoteUriHelper.cs +++ b/src/Components/src/Microsoft.AspNetCore.Components.Server/Circuits/RemoteUriHelper.cs @@ -61,14 +61,10 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits uriHelper.TriggerOnLocationChanged(); } - /// <summary> - /// Navigates to the specified URI. - /// </summary> - /// <param name="uri">The destination URI. This can be absolute, or relative to the base URI - /// (as returned by <see cref="IUriHelper.GetBaseUri"/>).</param> - protected override void NavigateToCore(string uri) + /// <inheritdoc /> + protected override void NavigateToCore(string uri, bool forceLoad) { - _jsRuntime.InvokeAsync<object>(Interop.NavigateTo, uri); + _jsRuntime.InvokeAsync<object>(Interop.NavigateTo, uri, forceLoad); } } } diff --git a/src/Components/src/Microsoft.AspNetCore.Components/Services/IUriHelper.cs b/src/Components/src/Microsoft.AspNetCore.Components/Services/IUriHelper.cs index e8deebaf346..b228570ffc3 100644 --- a/src/Components/src/Microsoft.AspNetCore.Components/Services/IUriHelper.cs +++ b/src/Components/src/Microsoft.AspNetCore.Components/Services/IUriHelper.cs @@ -51,5 +51,13 @@ namespace Microsoft.AspNetCore.Components.Services /// <param name="uri">The destination URI. This can be absolute, or relative to the base URI /// (as returned by <see cref="GetBaseUri"/>).</param> void NavigateTo(string uri); + + /// <summary> + /// Navigates to the specified URI. + /// </summary> + /// <param name="uri">The destination URI. This can be absolute, or relative to the base URI + /// (as returned by <see cref="GetBaseUri"/>).</param> + /// <param name="forceLoad">If true, 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.</param> + void NavigateTo(string uri, bool forceLoad); } } diff --git a/src/Components/src/Microsoft.AspNetCore.Components/Services/UriHelperBase.cs b/src/Components/src/Microsoft.AspNetCore.Components/Services/UriHelperBase.cs index 78f2c2fa9fa..aebf73aad55 100644 --- a/src/Components/src/Microsoft.AspNetCore.Components/Services/UriHelperBase.cs +++ b/src/Components/src/Microsoft.AspNetCore.Components/Services/UriHelperBase.cs @@ -45,9 +45,20 @@ namespace Microsoft.AspNetCore.Components.Services /// <param name="uri">The destination URI. This can be absolute, or relative to the base URI /// (as returned by <see cref="GetBaseUri"/>).</param> public void NavigateTo(string uri) + { + NavigateTo(uri, forceLoad: false); + } + + /// <summary> + /// Navigates to the specified URI. + /// </summary> + /// <param name="uri">The destination URI. This can be absolute, or relative to the base URI + /// (as returned by <see cref="GetBaseUri"/>).</param> + /// <param name="forceLoad">If true, 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.</param> + public void NavigateTo(string uri, bool forceLoad) { EnsureInitialized(); - NavigateToCore(uri); + NavigateToCore(uri, forceLoad); } /// <summary> @@ -55,7 +66,8 @@ namespace Microsoft.AspNetCore.Components.Services /// </summary> /// <param name="uri">The destination URI. This can be absolute, or relative to the base URI /// (as returned by <see cref="GetBaseUri"/>).</param> - protected abstract void NavigateToCore(string uri); + /// <param name="forceLoad">If true, 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.</param> + protected abstract void NavigateToCore(string uri, bool forceLoad); /// <summary> /// Called to initialize BaseURI and current URI before those values the first time. diff --git a/src/Components/test/Microsoft.AspNetCore.Components.E2ETest/Tests/RoutingTest.cs b/src/Components/test/Microsoft.AspNetCore.Components.E2ETest/Tests/RoutingTest.cs index f7d0f69e633..82991d47cc4 100644 --- a/src/Components/test/Microsoft.AspNetCore.Components.E2ETest/Tests/RoutingTest.cs +++ b/src/Components/test/Microsoft.AspNetCore.Components.E2ETest/Tests/RoutingTest.cs @@ -268,9 +268,33 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests SetUrlViaPushState("/"); var app = MountTestComponent<TestRouter>(); - app.FindElement(By.TagName("button")).Click(); + var testSelector = WaitUntilTestSelectorReady(); + + app.FindElement(By.Id("do-navigation")).Click(); + WaitAssert.True(() => Browser.Url.EndsWith("/Other")); WaitAssert.Equal("This is another page.", () => app.FindElement(By.Id("test-info")).Text); AssertHighlightedLinks("Other", "Other with base-relative URL (matches all)"); + + // 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")); + } + + [Fact] + public void CanNavigateProgrammaticallyWithForceLoad() + { + SetUrlViaPushState("/"); + + var app = MountTestComponent<TestRouter>(); + var testSelector = WaitUntilTestSelectorReady(); + + app.FindElement(By.Id("do-navigation-forced")).Click(); + WaitAssert.True(() => Browser.Url.EndsWith("/Other")); + + // Because this was a full-page load, our element references should no longer be valid + Assert.Throws<StaleElementReferenceException>(() => + { + testSelector.SelectedOption.GetAttribute("value"); + }); } [Fact] diff --git a/src/Components/test/testapps/BasicTestApp/RouterTest/Links.cshtml b/src/Components/test/testapps/BasicTestApp/RouterTest/Links.cshtml index 10c401898f7..1858b7e8327 100644 --- a/src/Components/test/testapps/BasicTestApp/RouterTest/Links.cshtml +++ b/src/Components/test/testapps/BasicTestApp/RouterTest/Links.cshtml @@ -13,10 +13,14 @@ <li><NavLink href="/subdir/WithParameters/Name/Abc/LastName/McDef">With parameters</NavLink></li> </ul> -<button onclick=@(x => uriHelper.NavigateTo("Other"))> +<button id="do-navigation" onclick=@(x => uriHelper.NavigateTo("Other"))> Programmatic navigation </button> +<button id="do-navigation-forced" onclick=@(x => uriHelper.NavigateTo("Other", true))> + Programmatic navigation with force-load +</button> + <a id="anchor-with-no-href"> Anchor tag with no href attribute </a> -- GitLab