In blazor i use NavigationManager.NavigateTo(url)
in order to change window location, but how can I use it to open a new tab with a specified URL without having to invoke JS on OnAfterRenderAsync()
As of 1 of June 2022 there is no way of currently doing it directly with pure Blazor, you'll need to use JSInterop. Luckily this is easy enough to do. At the top of your .razor
file add
@inject IJSRuntime JSRuntime;
And then use it like so
await JSRuntime.InvokeAsync<object>("open", url, "_blank");
Note that the IJSRuntime
interface itself only provides a InvokeAsync<TValue>
method, the JSRuntimeExtensions
class provides an extension method for IJSRuntime
to directly invoke a method without a return value: InvokeVoidAsync
await JSRuntime.InvokeVoidAsync("open", url, "_blank");
OnAfterRender
or can I run it from an onclick? –
Lauer await JsRuntime.InvokeAsync<object>("open", new object[] { "https://google.com/", "_blank" });
–
Lauer OnClick
because else most browsers will block it as it may not be a user initiated event –
Milkandwater InvokeVoidAsync
isn't specified on the IJSRuntime
interface. I updated the answer to add that part. Plus, I don't see how InvokeVoidAsync
avoids the exception, even after looking at the source code. Maybe it was fixed internally somewhere between I originally posted this answer and today –
Milkandwater InvokeVoidAsync
as an extension method. Using it does prevent the TaskCanceledexception
that was occurring about a minute after invocation, in my case at least. learn.microsoft.com/en-us/dotnet/api/… –
Involucre Formerly, this code worked.
await _jsRuntime.InvokeVoidAsync("open", new object[2] { url, "_blank" });
At present, it now results in an uncaught exception:
> "TypeError: Converting circular structure to JSON
I found this behavior explained here (https://github.com/dotnet/aspnetcore/issues/16632):
This is because window.open returns a WindowProxy object (see https://developer.mozilla.org/en-US/docs/Web/API/Window/open). WindowProxy is not JSON-serializable, so can't be used as a return value to .NET code.
To fix this, don't call window.open directly, but instead call a JS function of your own that either returns nothing or returns something that is JSON-serializable.
Per the above recommendation, I added the following to index.html:
<script>
window.blazorOpen = (args) => {
window.open(args);
};
</script>
And modified my C# code-behind call to pass the window arguments:
await _jsRuntime.InvokeVoidAsync("blazorOpen", new object[2] { url, "_blank" });
Effectively we now avoid the issue by discarding the WindowProxy object returned by window.open, which was formerly returned to InvokeVoidAsync and .NET was attempting to (unsuccessfully) process.
You will get TypeError: Converting circular structure to JSON
when using
await _jsRuntime.InvokeVoidAsync("open", new object[2] { url, "_blank" });
or
await _jsRuntime.InvokeAsync<object>("open", url, "_blank");
This is because
window.open
returns aWindowProxy
object (see https://developer.mozilla.org/en-US/docs/Web/API/Window/open).WindowProxy
is not JSON-serializable, so can't be used as a return value to .NET code.
Taken from see here.
To get around this w/o using a javascript function, I use the following
await JSRuntime.InvokeVoidAsync("eval", $"let _discard_ = open(`{url}`, `_blank`)");
Just use a regular link
<a href="@Url" target="_blank">@UrlDescription</a>
@onclick
event handler –
Lauer @onclick="@(async ()=>await JSRuntime.InvokeAsync<object>("open", url, "_blank"))"
–
Lauer @onclick
, which is a "pay" button, the link redirects to the payout page with certain tokens, now I could generate the link, then ask the user to click on another element, but that would require 2 clicks instead of 1 –
Lauer Per the latest change in API here is the working solution where you can add any custom object attribute to the URL as shown below:
/// <summary>
/// Show Link
/// </summary>
/// <returns></returns>
private async Task ShowLink()
{
if (this.selectedItem != null)
{
string url = $"https://example.com/sites/" + this.selectedItem.Id + "/SitePages/Reports/somepage.aspx";
//NavigationManager.NavigateTo(url, false);//opens the new page on same browser tab
string[] values = { url, "_blank" };
CancellationToken token = new CancellationToken(false);
await JSRuntime.InvokeAsync<object>("open", token, values);//opens the link in new browser tab
}
}
The best way is to:
<NavLink class="MyCssClass"
target="_blank"
href="https://www.google.com">
Google in new window
</NavLink>
.net 7+
you have to use await JSRuntime.InvokeVoidAsync("open", url, "_blank");
if you use JSRuntime.InvokeAsync<object>
it results in an error:
blazor.server.js:1 [2024-04-16T07:48:04.751Z] Error: Microsoft.JSInterop.JSException: Converting circular structure to JSON
--> starting at object with constructor 'Window'
--- property 'window' closes the circle
TypeError: Converting circular structure to JSON
--> starting at object with constructor 'Window'
--- property 'window' closes the circle
at JSON.stringify (<anonymous>)
at D (https://localhost:44326/_framework/blazor.server.js:1:5345)
at https://localhost:44326/_framework/blazor.server.js:1:3541
at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](Int64 targetInstanceId, String identifier, Object[] args)
© 2022 - 2024 — McMap. All rights reserved.
InvokeVoidAsync
– Milkandwater