Blazor : how to create a component

Blazor : how to create a component

Basics

Here are the different steps for the creation of a Blazor component with some javascript logic inside.

  1. Install Node.js

2.   Create a Blazor wasm project (MyComp.Tester)

This project will be useful to test your component.

3.    In the solution, add a Razor class project (MyComp)

This is where your component will be implemented.

4.    Add Microsoft.TypeScript.Build nuget package to MyComp

Optional but recommended. This package lets you write your logic in typescript instead of javascript which improves the overall readability of code. Typescript is transpiled into javascript at build time to be then used by your component at runtime.

5.     Generate and edit your tsconfig.json

Execute the following line from the root folder of MyComp

npx -p typescript tsc --init

You should now see a tsconfig.json file in your project.

Open it and change module: "commonjs" to module: "ES6".

Note: I've seen people do that in the project properties, in a category named TypeScript. It never worked for me, that's why I'm offering the node.js method here. There is also the option of creating the file manually.

6.      Add a typescript file in wwwroot

Add a file named mycomp.ts and add some code as shown below:

// By convention, use the same name as your razor component (not strictly required though)
class Component1 {
    public repeat(message: string) {
        alert(message);
    }
}

// In this code, the class is not accessible (has no export)
// The method below is exported and can be accessed through Js interop in C#.
// It'll help us get an instance of the class above
export function GetInstance() {
    return new Component1();
}

Note: Why can't I attach my .ts file directly to my C# component ?

The conventions designed by Microsoft let you add a .ts file to your razor class only for pages. If you take the Counter.razor.cs for instance, you can create a Counter.razor.ts in the same folder and it'll fall under the razor component. You can then invoke it with a relative path (./Shared/Counter.razor.js).

Unfortunately, this convention does not work with razor class projects. You must add your ts file in wwwroot, and it's gonna be available at ./_content/MyComp/mycomp.ts according to the following pattern : ./_content/<project_name>/<path under wwwroot>/script.js.

7.      Implement your js interop class

Use the provided example code and rename the class to ComponentJsInterop.
With our current ts file, all you need to do is edit the path to the js script with the one specified above, rename Prompt into Repeat  for clarity and change its implementation with the following:

public async ValueTask<string> Repeat(string message)
{
    await using var jsModule = await moduleTask.Value;
    var js = await jsModule!.InvokeAsync<IJSObjectReference>("GetInstance");
    await js.InvokeVoidAsync("repeat", "Welcome");
}

Note that if your .ts file specifies a namespace (just like in C#), the path to the js method must include the namespace. So if your namespace is mycomp, you should use mycomp.repeat in the example above.

8.       Implement your component

Edit your Component1.razor file and add the following

<div class="component1">
    What should I repeat: <input @bind="Message" />
    <br/>
    <button @onclick="Validate">Validate</button>
</div>

The component expects an input and will display that same input in an alert popup of the browser.

Create a Component1.razor.cs file or append @code {} to the html above to add the csharp logic. Here is how it would look like in a .cs file:

public partial class Component1 : IAsyncDisposable
{
    private ComponentJsInterop interop;

    [Inject]
    public IJSRuntime JSRuntime { get; set; } 

    // Binding value
    public string Message {get; set; } = "";

    // Click handler
    public async Task Validate()
    {
        await interop.Repeat(Message);
    }

    protected override void OnAfterRender(bool firstRender)
    {
        if(firstRender)
        {
            // On first rendering instantiate the interop
            interop = new ComponentJsInterop(JSRuntime);
        }
    }

    // Since interop is disposable, the component is disposable as well
    public async ValueTask DisposeAsync()
    {
        if(interop != null)
        {
            await interop.DisposesAsync();
        }
    }
}

9.      Use your component

In your MyComp.Tester.Client project, add a project reference to MyComp.
Now open the Counter page and simply add :

<Component1 />

Run the app and you should now see your component which should work as expected.