Basaingeal / Razor.SweetAlert2

A Razor class library for interacting with SweetAlert2

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Missing Stylesheet after navigating in .NET 8

UweKeim opened this issue · comments

Issue

After navigating away and back to a page, a call to Swal.FireAsync() shows an alert that has CSS missing.

Steps

I've created a new Blazor Web App with these configuration settings:

image

I then added

<PackageReference Include="CurrieTechnologies.Razor.SweetAlert2" Version="5.5.0" />

to my project's CSPROJ file, added

<script src="_content/CurrieTechnologies.Razor.SweetAlert2/sweetAlert2.min.js"></script>

right to the end before the </body> tag:

image

and added this to my "Program.cs":

builder.Services.AddSweetAlert2(options =>
{
	options.Theme = SweetAlertTheme.Dark;
	options.SetThemeForColorSchemePreference(ColorScheme.Light, SweetAlertTheme.Default);
	options.SetThemeForColorSchemePreference(ColorScheme.Dark, SweetAlertTheme.Dark);
});

Next, I created a simple button in "Home.razor":

<button @onclick="@(async ()=>await Swal.FireAsync("Test!"))">Test, klick!</button>

I've also changed @rendermode InteractiveServer on that page. The full source code of the page looks like this:

@page "/"
@rendermode InteractiveServer
@inject SweetAlertService Swal

<PageTitle>Home</PageTitle>

<h1>Hello, world!</h1>

Welcome to your new app.

<button @onclick="@(async ()=>await Swal.FireAsync("Test!"))">Test, klick!</button>

This results in this:

image

When I click the button, it shows this alert:

image

I can do this multiple times successfully.

Next, I navigate to another page:

image

And then I navigate back to the home page:

image

When I then click the button, the alert appears, but it seems to have no styling:

image

It is shown that the bottom left of the page.

It seems to work correctly (i.e. I can click the OK button to close the alert), but it looks wrong.

Expected behavior

I would expect that Razor.SweetAlert2 works every time, not just when I do not navigate.

Desktop

  • OS: Windows 11 German, 64 bit
  • Browser: Google Chrome Version 120.0.6099.71 (Offizieller Build) (64-Bit)

Any workaround? Same problem here...

It seems, that all my favorite Blazor library developers have shifted priorities away from .NET 8 Blazor 😭.

I have the same problem.

I found a workaround. This is because of the new Blazor SSR, it changes the way that JS is rendered.

You need to use PageScript: https://github.com/MackinnonBuck/blazor-page-script

Import the SweetAlert2 Script in the MainLayout like this: <PageScript Src="./_content/CurrieTechnologies.Razor.SweetAlert2/sweetAlert2.min.js" />

Set a RenderMode for HeadOutlet like this: <HeadOutlet @rendermode="new InteractiveAutoRenderMode(prerender: false)" />

With this trick everything should be working just fine.

This trick solved issues with all JS-based libraries I've imported.

Source: https://learn.microsoft.com/en-us/aspnet/core/blazor/javascript-interoperability/static-server-rendering?view=aspnetcore-8.0

In case anyone wonders: The NuGet package of PageScript is named "BlazorPageScript".

And you have to add this to "_Imports.razor":

...
@using BlazorPageScript
...

@Pvxtotal When doing your steps, I get an error:

InvalidOperationException: A component of type 'Microsoft.AspNetCore.Components.Web.HeadOutlet' has render mode 'InteractiveAutoRenderMode', but the required endpoints are not mapped on the server. When calling 'MapRazorComponents', add a call to 'AddInteractiveWebAssemblyRenderMode'. For example, 'builder.MapRazorComponents<...>.AddInteractiveWebAssemblyRenderMode()'

Could you please share some more code of your solution?

@UweKeim in your case use HeadOutlet like this: <HeadOutlet @rendermode="new InteractiveServerRenderMode(prerender: false)" />

Thanks, @Pvxtotal, I've already tried that, too, without success.

I've changed the <HeadOutlet /> in mit "App.razor" to:

<HeadOutlet @rendermode="new InteractiveServerRenderMode(prerender: false)" />

I removed this from the "App.razor":

<script src="_content/CurrieTechnologies.Razor.SweetAlert2/sweetAlert2.min.js"></script>

And then I've added this to "MainLayout.razor":

<HeadContent>
	<PageScript Src="_content/CurrieTechnologies.Razor.SweetAlert2/sweetAlert2.min.js" />
</HeadContent>

When clicking the button to show a SweetAlert2 dialog, I get this error:

Error: Microsoft.JSInterop.JSException: Could not find 'CurrieTechnologies.Razor.SweetAlert2.Fire' ('CurrieTechnologies' was undefined).

With this call stack:

Error: Could not find 'CurrieTechnologies.Razor.SweetAlert2.Fire' ('CurrieTechnologies' was undefined).
    at https://localhost:7133/_framework/blazor.web.js:1:734
    at Array.forEach (<anonymous>)
    at l.findFunction (https://localhost:7133/_framework/blazor.web.js:1:702)
    at b (https://localhost:7133/_framework/blazor.web.js:1:5445)
    at https://localhost:7133/_framework/blazor.web.js:1:3238
    at new Promise (<anonymous>)
    at y.beginInvokeJSFromDotNet (https://localhost:7133/_framework/blazor.web.js:1:3201)
    at fn._invokeClientMethod (https://localhost:7133/_framework/blazor.web.js:1:62541)
    at fn._processIncomingData (https://localhost:7133/_framework/blazor.web.js:1:60016)
    at connection.onreceive (https://localhost:7133/_framework/blazor.web.js:1:53657)
   at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](Int64 targetInstanceId, String identifier, Object[] args)
   at CurrieTechnologies.Razor.SweetAlert2.SweetAlertService.FireAsync(String title, String message, SweetAlertIcon icon)
   at BlazorApp6.Components.Pages.Home.<BuildRenderTree>b__0_1() in C:\Users\ukeim\Documents\Visual Studio 2022\Projects\BlazorApp6\Components\Pages\Home.razor:line 11
   at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)

Probably I'm missing something but can't figure out what.

@UweKeim  Change it to: <PageScript Src="./_content/CurrieTechnologies.Razor.SweetAlert2/sweetAlert2.min.js" />

./ at the start

Thanks again, @Pvxtotal, I've also tried this without success.

It seems that I solved it by not placing the <PageScript... component into the <HeadContent> tags, but simply at the very end of the "MainLayout.razor" page:

<PageScript Src="/_content/CurrieTechnologies.Razor.SweetAlert2/sweetAlert2.min.js" />

I still have to have this in the "App.razor":

<HeadOutlet @rendermode="new InteractiveServerRenderMode(prerender: false)" />

But all after all, it seems to work.

Sorry for my absence. I'll be looking into this, but .NET 8 runtime support has been added. That may aleviate this issue, but if there is a breaking change in .NET 8 I'll need to work out a fix.

@Basaingeal This is related to how Blazor SSR load scripts when enhanced navigation is on. If you disable enhanced navigation everything works fine. I still don't know any workaround besides disabling enhanced navigation or turning the entire app into Interactive.

Source: dotnet/aspnetcore#52273

Work for me adding only this line @rendermode="@RenderMode.InteractiveServer" on app.razor in HeadOutlet and Routes also works fine with @rendermode="@(new InteractiveServerRenderMode(false))"

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <base href="/" />
    <link rel="stylesheet" href="bootstrap/bootstrap.min.css" />
    <link rel="stylesheet" href="app.css" />
    <link rel="stylesheet" href="Biblioteca.Server.styles.css" />
    <link rel="icon" type="image/png" href="favicon.png" />
    <HeadOutlet @rendermode="@RenderMode.InteractiveServer"/>
</head>

<body>    
    <Routes @rendermode="@RenderMode.InteractiveServer" />
    <script src="_framework/blazor.web.js"></script>
    <Script src="_content/CurrieTechnologies.Razor.SweetAlert2/sweetAlert2.min.js"></Script>
</body>

Hi muadyb, your solution worked fine for me, Thanks four you help :)!

Work for me adding only this line @rendermode="@RenderMode.InteractiveServer" on app.razor in HeadOutlet and Routes also works fine with @rendermode="@(new InteractiveServerRenderMode(false))"

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <base href="/" />
    <link rel="stylesheet" href="bootstrap/bootstrap.min.css" />
    <link rel="stylesheet" href="app.css" />
    <link rel="stylesheet" href="Biblioteca.Server.styles.css" />
    <link rel="icon" type="image/png" href="favicon.png" />
    <HeadOutlet @rendermode="@RenderMode.InteractiveServer"/>
</head>

<body>    
    <Routes @rendermode="@RenderMode.InteractiveServer" />
    <script src="_framework/blazor.web.js"></script>
    <Script src="_content/CurrieTechnologies.Razor.SweetAlert2/sweetAlert2.min.js"></Script>
</body>

Hi muadyb, your solution worked fine for me, Thanks four you help :)!

    <Routes />
    <script src="_framework/blazor.web.js"></script>
    <script src="_content/CurrieTechnologies.Razor.SweetAlert2/sweetAlert2.min.js"></script>

    <script>
        function injectScript(url) {
            const script = document.createElement('script');
            script.src = url;
            document.head.appendChild(script);
        }

        Blazor.addEventListener('enhancedload', () => {
            const oldScript = document.querySelector('script[src="_content/CurrieTechnologies.Razor.SweetAlert2/sweetAlert2.min.js"]');
            if (oldScript) {
                oldScript.remove();
            }

            injectScript('_content/CurrieTechnologies.Razor.SweetAlert2/sweetAlert2.min.js');
        });

    </script>
i've found another workaround to make it work with Blazor SSR. Just remove and insert the script on each navigation. This applies to every JS interaction with Blazor SSR