Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I open a new window without using JS

Tags:

c#

signalr

blazor

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()

like image 868
Flexy Avatar asked Jul 07 '20 06:07

Flexy


4 Answers

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.

like image 82
Mike Avatar answered Nov 18 '22 11:11

Mike


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");
like image 38
MindSwipe Avatar answered Nov 18 '22 12:11

MindSwipe


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 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.

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`)");
like image 4
wdcossey Avatar answered Nov 18 '22 12:11

wdcossey


Just use a regular link

<a href="@Url" target="_blank">@UrlDescription</a>
like image 3
Mister Magoo Avatar answered Nov 18 '22 10:11

Mister Magoo