Full Trust European Hosting

BLOG about Full Trust Hosting and Its Technology - Dedicated to European Windows Hosting Customer

European Blazor Hosting - HostForLIFE :: Blazor Route Parameter

clock June 20, 2022 10:12 by author Peter

In this article, we are going to discuss route parameters in Blazor. A route parameter is defined in the URL by wrapping its name in a pair of {braces} along with @page declaration.

Example; @page “/employee/{employeeId}

For this tutorial I’m using Microsoft Visual Studio Community 2022 (64-bit) – Preview with Version 17.2.0 Preview 5.0.

Parameter value capture

Value of a parameter can be captured by simply adding a property with the same name and decorating it with an attribute [Parameter]
[Parameter]
public string FruitCode { get; set; }

For demo purposes, I’m using the Counter.razor component in which I am adding three anchor tags with parameter value
<li><a href="/counter/Orange">Orange</a></li>
<li><a href="/counter/Mango">Mango</a></li>
<li><a href="/counter/Apple">Apple</a></li>

The route will look like below
@page "/counter"
@page "/counter/{FruitCode}"


Here {FruitCode} is the parameter

When you click on Orange – the value “Orange” will be passed as parameter in the URL

If you look at the image, in the address bar, you can see that “Orange” has been passed and the same has been displayed as “Selected Fruit: Orange”. The entire code from Counter.razor component has been given below for reference.
@page "/counter"
@page "/counter/{FruitCode}"
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<p role="banner"> Selected Fruite : @FruitCode</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
<h1>Select a Fruit</h1>
<ul>
  <li><a href="/counter/Orange">Orange</a></li>
  <li><a href="/counter/Mango">Mango</a></li>
  <li><a href="/counter/Apple">Apple</a></li>
</ul>
@code {
    private int currentCount = 0;
 [Parameter]
    public string FruitCode { get; set; }
    private void IncrementCount()
    {
        currentCount++;
    }
}

Note
As we are navigating to the same page,

    The component will not be destroyed before navigation.
    OnInitialized lifecycle methods will not be executed.

Route Parameter Constraints
To define a constraint for a parameter it is suffixed with a colon and then the constraint type. For example, :int will only match the component’s URL if it contains a valid integer value in the right position.

The route looks like below
@page "/counter"
@page "/counter/{CurrentCount:int}"


Please refer to the Microsoft documentation for more details.
Thank you for reading my article. Please leave your comments in the comment box below.



European Blazor Hosting - HostForLIFE :: TypeScript With Blazor

clock November 26, 2021 07:36 by author Peter

This particular blog will help you to setup and use TypeScript in a Blazor client project.

What is TypeScript ?
TypeScript is a strongly typed programing language built on top of Javascript. TypeScript have lot of pros over the Javascript which includes the power of Object Oriented Programing. TypeScript supports concepts from Object Oriented Programing and will be able to build a scalable and well organised code compared to JavaScript. TypeScript is always very much predictable. Everything in it always stays in the same way it was defined, if you decalre a variable with a type as boolean , it will always stays as boolean.
How to integrate TypeScript with Blazor?

In order to integrate TypeScript with blazor we can follow the below steps,
Install Microsoft.TypeScript.MSBuild nuget package in Blazor client project
Create a TypeScript File in the project
Create a class and the method which to be invoed from blazor C# code

ex

namespace common {
    class Prompt {
        public showAlert() {
            alert("thhis is a test");
        }
    }
}


Now we need to create a method which will return an instance of Prompt class.
export function getPromptInstance(): Prompt {
    return new Prompts();
}


Thats all from TypeScript side. Now lets move to C# side.
Create a Blazor component from where we need to access this type script method
Invoke the getPromptInstance() to get the instance of Prompt class from the razor or cs file using IJSRuntime object.

ex
var promptObject = await this._jSRuntime.InvokeAsync<IJSObjectReference>("common.getPromptInstance");

Now we can invoke the showAlert() using the prompt object
await promptObject.InvokeVoidAsync("showAlert");

Rebuild the solution and make sure .js and .js.map version of newly added TypeScript file has been created as below



European Blazor Hosting - HostForLIFE :: Blazor - JavaScript Isolation (ES6 Modules & Blazor)

clock November 16, 2021 07:16 by author Peter

When using JavaScript in Blazor, we typically add the reference to our JavaScript files in _Host.cshtml. This allows us to access our JavaScript from anywhere in our Blazor application.

Since Blazor apps are SPAs (Single-Page Applications), it makes sense why it works this way. But, we often don’t want to pollute the global JavaScript namespace with every function and variable. Often, an individual component will need its own JavaScript to work correctly. How can we isolate JavaScript code to a single component?
Objects As Namespaces

One solution you might find online is to wrap all JavaScript code in objects, effectively making namespaces for each component:
window.MyNamespace = {
    MyFunction: function() {
        ...
    },
};


This works, but it is cumbersome to work with and all of these objects are still globally visible. We still don’t have true isolation.

Luckily, JSInterop in Blazor supports ES6 Modules.

Using ES6 Modules in Blazor
Modules in JavaScript allow us to completely isolate scripts from the global namespace. With a module, only the components that import it can access it, and only code that is explicitly exported within the module can be accessed. This allows us to tightly control access to our code and removes namespace pollution in large projects.

Let’s say we have a component that displays the start time of an event. This start time is stored in our system and displayed as UTC, but when the user clicks a button, we want the displayed time converted to their local timezone. We can do this with the help of JavaScript, since the browser has access to the user's timezone.

First let's create a Blazor Component called TimeDisplay.
[TimeDisplay.razor]

<p>Event starts at: @displayTime.ToString("g")</p>
<button class="btn btn-primary" @onclick="OnClick">Click me</button>
@code {
    private DateTime displayTime = DateTime.UtcNow;
    private void OnClick() {}
}


For this example, we need to utilize JavaScript to get the user’s local timezone. The rest of the web app doesn’t care about this timezone logic, so we want to isolate it to our TimeDisplay component.

Within the project’s wwwroot folder, we can create a folder called scripts then create a subfolder called components

Then, we add our .js file in this folder,

 

Let’s write some JavaScript. We want a JavaScript function we can call from C# that lets us pass in a DateTime string in UTC, and it’ll return to us converted into the user’s timezone.

function ConvertStartTimeToLocal(utcDateTime) {
    const utcString = new Date(`${utcDateTime} UTC`);
    return utcString.toLocaleString();
}

Now, typically we would add the reference to this script in _Host.cshtml (In Blazor Server) so that we can access it via the JSInterop features.

But since this JavaScript only corresponds to an individual component, it would be ideal if the component itself could load this JavaScript file.
Loading the script in our Component

To begin, we will still need to [Inject] an IJSRuntime instance like normal so that we can do JS Interop.

The difference is that instead of calling JavaScript functions with the IJSRuntime instance directly, we will use it to import our module and store it as an IJSObjectReference instance.
// TimeDisplay.razor
@code {
[Inject] IJSRuntime JSRuntime { get; set; }
IJSObjectReference module;


JavaScript won’t be usable in a component until after the component is rendered to the client, so we must initialize it within the OnAfterRenderAsync method.
protected override async Task OnAfterRenderAsync(bool firstRender)
{
    module = await JSRuntime.InvokeAsync<IJSObjectReference>("import", "./scripts/components/TimeDisplay.js");
}


With this code, instead of calling the JavaScript function directly using the IJSRuntime, we are instead using the import feature of ES6 to import our module. This module is stored as an IJSObjectReference instance, which we can use to communicate with our module directly.

Now let’s implement the button’s OnClick method.
private async Task OnClick()
{
    var converted = await module.InvokeAsync<string>("ConvertStartTimeToLocal",
    displayTime.ToString("g"));
    displayTime = DateTime.Parse(converted);
}


Note carefully, we are using module.InvokeVoidAsync instead of JSRuntime.InvokeVoidAsync. This is the key difference here. We are not calling code from the global JS runtime, we are only accessing code from within our module. Everything else you know about how to use JS Interop stays exactly the same.

Finally, let's go to Index.razor and add our component
<TimeDisplay />

There's a slight catch
If we are using a module, we need to make sure we explicitly dispose of it for garbage collection. If we don't, the JSRuntime will continue holding a reference to our module for the lifetime of the application.

To do this, our component must implement IAsyncDisposable, then we can dispose of our module in the DisposeAsync method.
Here's the completed TimeDisplay component:
@implements IAsyncDisposable
<p>Event starts at: @displayTime.ToString("g")</p>
<button class="btn btn-primary" @onclick="OnClick">Click me</button>
@code {
    [Inject] IJSRuntime JSRuntime {
        get;
        set;
    }
    IJSObjectReference module;
    private DateTime displayTime = DateTime.UtcNow;
    protected override async Task OnAfterRenderAsync(bool firstRender) {
        module = await JSRuntime.InvokeAsync < IJSObjectReference > ("import", "./scripts/components/TimeDisplay.js");
    }
    private async Task OnClick() {
        var converted = await module.InvokeAsync < string > ("ConvertStartTimeToLocal", displayTime.ToString("g"));
        displayTime = DateTime.Parse(converted);
    }
    async ValueTask IAsyncDisposable.DisposeAsync() {
        if (module is not null) {
            await module.DisposeAsync();
        }
    }
}


Let’s run the app. Once the page loads, click on the button and see the result

Woops! We are seeing this error because with ES6 modules, only code that is marked with export can be seen from outside the module. There are a couple of ways to do this, and I’ll show both, but I prefer one over the other and I’ll explain why later.

The change we need to make is very simple, and we don’t need to stop or restart the app.

Note
In Blazor, you don’t need to restart the app after changing JavaScript code. You can just refresh the page after saving the file to see the changes in action.

We will just add the export keyword in front of the function declaration:
export function ConvertStartTimeToLocal(utcDateTime) {
    const utcTimeString = new Date(`${utcDateTime} UTC`);
    return utcTimeString.toLocaleString();
}

Save the file, then refresh the page and try again. You should see the time converted to your local time when the button is clicked.

On the topic of export
Now, as was mentioned previously there is another way to export code out of a JS module, and it’s done like so:
function ConvertStartTimeToLocal(utcDateTime) {
    const utcTimeString = new Date(`${utcDateTime} UTC`);
    return utcTimeString.toLocaleString();
}
export { ConvertStartTimeToLocal };


Both ways of exporting are acceptable. But, I personally prefer putting export before the function/variable declaration. Here’s why: When marking a function or variable explicitly as export function or export const, you can immediately tell just by reading the function declaration that the code is intended to be called from a Blazor component.

Functions and variables declared with export are clearly being used from C# with JSInterop

Functions and variables declared without export are local to the module and won’t be used by C# code

A list of exports at the bottom of the code file makes this far less obvious, in my opinion.

This module feature is, in my opinion, a hidden gem in Blazor. It allows you to write JavaScript files as if everything were global—not worrying about namespacing. The file itself is the namespace!

Stay safe everyone and happy coding!



About HostForLIFE

HostForLIFE is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes.

We have offered the latest Windows 2019 Hosting, ASP.NET 5 Hosting, ASP.NET MVC 6 Hosting and SQL 2019 Hosting.


Tag cloud

Sign in