I have a .NET 8 Core Blazor page with Authentication. My App.razor contains the following html and code.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<base href="/" />
<link href="https://fonts.googleapis.com/css2?family=Montserrat&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Macondo&display=swap" rel="stylesheet">
<link rel="stylesheet" href="" id="userStylesheet" data-permanent />
<link rel="stylesheet" href="css/CardFlip.css" />
<link href="css/site.css" rel="stylesheet" />
<link rel="stylesheet" href="css/cutealert.css" />
<link rel="stylesheet" href="css/fontawesome.css" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<HeadOutlet @rendermode="RenderModeForPage" />
</head>
<body>
<Routes @rendermode="RenderModeForPage" />
<script>window.$ = window.jQuery = require('jquery');</script>
<script src="js/all.min.js"></script>
<script src="js/Jquery.js"></script>
<script src="js/bootstrap.bundle.min.js"></script>
<script src="js/ShowModal.js"></script>
<script src="js/cute-alert.js"></script>
<script src="js/jspdf.min.js"></script>
<script src="js/html2canvas.js"></script>
<script src="js/html2pdf.bundle.min.js"></script>
<script src="_framework/blazor.server.js"></script>
</body>
</html>
@code {
[CascadingParameter]
private HttpContext HttpContext { get; set; } = default!;
private IComponentRenderMode? RenderModeForPage => HttpContext.Request.Path.StartsWithSegments("/Account")
? null
: InteractiveServer;
}
I have a global theme I am trying to apply to all of my pages and I do that with a javascript function.
function ChangeStyleSheet(newSheet) {
var linkTag = document.getElementById('userStylesheet');
linkTag.href = newSheet;
}
The problem is that I cannot seem to call this function when I am rendering in SSR. That is anytime I load in a page from /Account, it renders SSR. Other pages render in Interactive Server. I can easily call the javascript function using JSRuntime when rendered in Interactive server.
I found a microsoft page which discusses Javascript in SSR where it seems to create a component called PageScript and another js module which you create which I am unsure its purpose. Yet I still do not see in that example how I am supposed to call ChangeStyleSheet from an SSR page.
Does anyone have a solution? If I need to add more information, please let me know and I will certainly add it.
If you want to follow the official document to call js from a SSR page. Follow the steps below:
Add the following JavaScript initializer to the server project's wwwroot folder. The {NAME}
placeholder must be the name of the app's assembly in order for Blazor to locate and load the file automatically. If the server app's assembly name is BlazorSample
, the file is named BlazorSample.lib.module.js
.
wwwroot/{NAME}.lib.module.js
:
const pageScriptInfoBySrc = new Map();
function registerPageScriptElement(src) {
if (!src) {
throw new Error('Must provide a non-empty value for the "src" attribute.');
}
let pageScriptInfo = pageScriptInfoBySrc.get(src);
if (pageScriptInfo) {
pageScriptInfo.referenceCount++;
} else {
pageScriptInfo = { referenceCount: 1, module: null };
pageScriptInfoBySrc.set(src, pageScriptInfo);
initializePageScriptModule(src, pageScriptInfo);
}
}
function unregisterPageScriptElement(src) {
if (!src) {
return;
}
const pageScriptInfo = pageScriptInfoBySrc.get(src);
if (!pageScriptInfo) {
return;
}
pageScriptInfo.referenceCount--;
}
async function initializePageScriptModule(src, pageScriptInfo) {
if (src.startsWith("./")) {
src = new URL(src.substr(2), document.baseURI).toString();
}
const module = await import(src);
if (pageScriptInfo.referenceCount <= 0) {
return;
}
pageScriptInfo.module = module;
module.onLoad?.();
module.onUpdate?.();
}
function onEnhancedLoad() {
for (const [src, { module, referenceCount }] of pageScriptInfoBySrc) {
if (referenceCount <= 0) {
module?.onDispose?.();
pageScriptInfoBySrc.delete(src);
}
}
for (const { module } of pageScriptInfoBySrc.values()) {
module?.onUpdate?.();
}
}
export function afterWebStarted(blazor) {
customElements.define('page-script', class extends HTMLElement {
static observedAttributes = ['src'];
attributeChangedCallback(name, oldValue, newValue) {
if (name !== 'src') {
return;
}
this.src = newValue;
unregisterPageScriptElement(oldValue);
registerPageScriptElement(newValue);
}
disconnectedCallback() {
unregisterPageScriptElement(this.src);
}
});
blazor.addEventListener('enhancedload', onEnhancedLoad);
}
Add the following shared PageScript
component to the server app.
Components/PageScript.razor
:
<page-script StyleSheetUrl="@StyleSheetUrl"></page-script>
<script>
document.addEventListener('DOMContentLoaded', function () {
ChangeStyleSheet('@StyleSheetUrl');
});
</script>
<script src="/test.js"></script>
@code {
[Parameter] public string StyleSheetUrl { get; set; } = "app.css";
}
Account.razor
:
@page "/Account"
<PageScript StyleSheetUrl="test.css" />
js function ChangeStyleSheet
locates in wwwroot/test.js
:
function ChangeStyleSheet(newSheet) {
var linkTag = document.getElementById('userStylesheet');
alert(linkTag);
linkTag.href = newSheet;
}