4

I'm fairly new to Razor Components and I would like to change the title and other data inside the HTML-document-head depending on what page a user visits (e.g. if a user visits the product page of product X, I want to change the title and other relevant data in the head accordingly). I already had a look at https://github.com/aspnet/Blazor/issues/1311#issuecomment-470760857 but the presented solutions look a bit hacky. I also know that I could theoretically use JavaScript interop to achieve my goals, but that also seems to be a bit messy.

I tried to render the app like this:

@page "{*clientPath}"

<!DOCTYPE html>
<html>
    @(await Html.RenderComponentAsync<App>())
</html>

But the attempt failed due to an error in components.server.js (Uncaught Error: There is no browser renderer with ID 0.). I know I shouldn't place JavaScript-tags into components, but I thought I would give it a try.

Hope you guys can help me. Thanks for reading. :)

2 Answers2

0

Here is how honkmother(https://github.com/honkmother) did it. Here is the link: https://github.com/aspnet/Blazor/issues/842#issuecomment-490671409

The Index.cshtml:

@page "{*clientPath}"

<!DOCTYPE html>
<html>

@(await Html.RenderComponentAsync<html>())

</html>

Then two classes called "html" and "metatags". The html class creates the html tags and store the header (script tags, etc) inside of a html file that is injected as markup.

public class html : ComponentBase
{
    public static string HeadTXT = File.ReadAllText("head.htm");
    Metatags meta = new Metatags() { Title = "some title" };
    protected override void BuildRenderTree(Microsoft.AspNetCore.Components.RenderTree.RenderTreeBuilder builder)
    {

        builder.OpenElement(0, "head");
        builder.AddMarkupContent(1, HeadTXT);
        builder.OpenComponent<Head>(2);
        builder.AddAttribute(3, "MetaInfo", meta);
        builder.CloseComponent();
        builder.CloseElement();

        builder.OpenElement(4, "body");
        builder.OpenComponent<Body>(5);
        builder.AddAttribute(6, "MetaInfo", meta);
        builder.CloseComponent();
        builder.AddMarkupContent(7, "<script src=\"_framework/components.server.js\"></script>");
        builder.CloseElement();

    }
}

public class Metatags
{
    public string Title { get; set; } = "example.nyc — weirdest hack ever";
    public string Description { get; set; } = "testing";
    public Head Component;
}

A "body" Component.

<DetectPrerender MetaInfo="@MetaInfo">
    <Router AppAssembly="typeof(Startup).Assembly" />
</DetectPrerender>


@functions {

    [Parameter]
    private Metatags MetaInfo { get; set; }

}

And a "head" component.

@using example.Shared

<title>@MetaInfo.Title</title>
<meta name="description" content="@MetaInfo.Description">
@{
    MetaInfo.Component = this;
}
@functions {

    [Parameter]
    private Metatags MetaInfo { get; set; }
    private bool ShouldRend = false;
    protected override bool ShouldRender()
    {
        if (ShouldRend)
        {
            ShouldRend = false;
            return true;
        }
        return false;
    }

    public void ShouldRe()
    {
        ShouldRend = true;
        base.Invoke(() => base.StateHasChanged());
    }

}
gorhal
  • 459
  • 7
  • 13
0

I found a NuGet that makes it very simple: Toolbelt.Blazor.HeadElement

Startup.cs

using Toolbelt.Blazor.Extensions.DependencyInjection;

 public void ConfigureServices(IServiceCollection services)
    {
        services.AddHeadElementHelper();

Then all you have to do is add the component to your page:

@page "/customers"

<Toolbelt.Blazor.HeadElement.Title>
    Customers
</Toolbelt.Blazor.HeadElement.Title>
<h1>Customers</h1>

The result will be

<title>customers<title> 

in your head section. This plugin also has components for meta tags and links.

William Mendoza
  • 327
  • 2
  • 4