Blazor tutorial for beginners - part 2
以 Blazor Server App 入門教學為主。
JS Interop: Calling JavaScript from C# | Blazor Tutorial 5
IJSRuntime
: You can call JS code from C#JSInvokableAttribute
:You call call C# code from JS
JS Interop : JavaScript Interoperability
@page "/jsinterop"
@inject IJSRuntime jsRuntime
<h1>JavaScript Interoperability Demo</h1>
<h4>Show Alert</h4>
<input @bind-value="message" />
<button class="btn btn-success" @onclick="ShowAlert">Show Alert</button>
<h4>Call Prompt</h4>
<p>一進入畫面就 focus 到這裡。</p>
<input @ref="inputRef" @bind-value="question" />
<button class="btn btn-warning" @onclick="AskQuestion">Ask question</button>
<div>
答案是:<span style="color:mediumvioletred" id="answerSpan"></span>
</div>
<h4>Foucs Element</h4>
<button class="btn btn-secondary" @onclick="FocusElement">Focus on Call Prompt</button>
@code{
string message = "我是來自C#的文字訊息。";
string question = "今天象氣如何?";
ElementReference inputRef;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender) {
await FocusElement();
}
}
async Task ShowAlert()
{
//string msg = "我是來自C#的文字訊息。";
await jsRuntime.InvokeVoidAsync("showAlert", message);
}
async Task AskQuestion()
{
var response = await jsRuntime.InvokeAsync<string>("showPrompt", question);
await jsRuntime.InvokeVoidAsync("setElementTextById", "answerSpan", response);
}
async Task FocusElement()
{
await jsRuntime.InvokeVoidAsync("focusElement", inputRef);
}
}
function showAlert(msg) {
alert(msg);
}
function showPrompt(question) {
return prompt(question);
}
function setElementTextById(id, text) {
document.getElementById(id).innerText = text;
}
function focusElement(element) {
element.focus();
}
JS Interop: Calling C# methods from JavaScript | Blazor Tutorial 6
由 JS 為啟始向 C# 呼叫函式(資源)應該是不會有此應用情境的,實務上應該用不到也不建議採用JS call CS code,因為 Blazor 的前端資源並不豐富且程式碼繞好大一圈。
但是,由 C# 為啟始向 JS 呼叫函式(資源)現況是必然的,再由 JS 向 C# 呼叫回覆函式也是常有的應用情境, ,因為前端資訊交換機制常是非同步 event-base 的。
C# ---(call/ask resource)---> JS
JS do processing
JS ---(invoke/reply message)---> C#
下面範例有
IJSRuntime
to call global JS function.
IJSObjectReference
import JavaScript function.
used to invoke JS function that imported.
DotNetObjectReference
、JSInvokable
used to let JS invoke the C# function.
程式碼紀錄:IdleWidget.razor、GlobalIdleTimer.js
目的:idle 時間太長自登出。
透過IJSObjectReference
與IJSRuntime
介面,動態載入 JS moudle。
使用ElementReference
傳遞 Element 給 JavaScript 更新。
使用 DotNetObjectReference
傳遞JSInvokable
函式讓JavaScript可以回呼(callback)。
@using Microsoft.JSInterop.Implementation
@inject IJSRuntime jsr
@inject NavigationManager navMan
<span @ref="displayRef" class="mx-1">idle</span>
@code{
#region Resource
IJSObjectReference module;
ElementReference displayRef;
#endregion
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);
if (firstRender)
{
// 動態載入 JS module
module = await jsr.InvokeAsync<IJSObjectReference>("import", "./js/GlobalIdleTimer.js");
// 啟動 Idel 計數器
await module.InvokeVoidAsync("Start", DotNetObjectReference.Create(this), displayRef);
}
}
/// <summary>
/// 當Idel計數到達時觸發
/// </summary>
[JSInvokable] //--- 讓JavaScript可以回呼
public Task<int> OnIdleTimeout(int _idleCount)
{
//## idle 時間太長自動登出。
navMan.NavigateTo("/Signout"); // 登出
return Task.FromResult(0);
}
}
監測使用者是否有在使用滑鼠鍵盤等輸入,並累計idle時間,若達到門檻就觸發訊息以登出系統。
/// state
let idle_timer = 0;
const IDLE_TIMEOUT = 5 * 20; // 5分鐘。三秒累計1次則每分鐘累計20次;
/// resource holder
let intervalId; // timer handler
let _dotNetObject; // 將指向來自C#的Razor元件
let _displayRef; // 將指向element
export function Start(dotNetObject, displayRef) {
_dotNetObject = dotNetObject;
_displayRef = displayRef;
document.addEventListener('click', resetGlobalIdleIimer);
document.addEventListener('mousemove', resetGlobalIdleIimer);
document.addEventListener('mouseenter', resetGlobalIdleIimer);
document.addEventListener('keydown', resetGlobalIdleIimer);
document.addEventListener('scroll', resetGlobalIdleIimer);
document.addEventListener('touchstart', resetGlobalIdleIimer);
intervalId = setInterval(increaseGlobalIdleIimer, 3000); // 每3秒累加一次計數
};
//export function Release() {
// clearInterval(intervalId);
// document.removeEventListener('click', resetGlobalIdleIimer);
// document.removeEventListener('mousemove', resetGlobalIdleIimer);
// document.removeEventListener('mouseenter', resetGlobalIdleIimer);
// document.removeEventListener('keydown', resetGlobalIdleIimer);
// document.removeEventListener('scroll', resetGlobalIdleIimer);
// document.removeEventListener('touchstart', resetGlobalIdleIimer);
//}
function increaseGlobalIdleIimer() {
idle_timer++;
//console.log('idle_timer', idle_timer);
// 更新UI
if (_displayRef)
_displayRef.innerHTML = idle_timer;
//## idle timeout,誤差為一次計數
if (idle_timer > IDLE_TIMEOUT) {
// 達到idle門檻,送出訊息以登出系統。
_dotNetObject.invokeMethodAsync('OnIdleTimeout', idle_timer);
}
}
function resetGlobalIdleIimer() {
idle_timer = 0;
//console.log('idle_timer', idle_timer);
}
Creating Forms with Validation | Blazor Tutorial 7
詳情請參考附件。
Blazor 提供了幾個表單操作元件系結表單:
<EditForm />
取代 <form /> 標籤。<DataAnnotationValidator />
<ValidationSummary/>
<ValidationMessage/>
也提供內建表單 input (Built-in form components)元件:
輸入元件
呈現為…
<input type="checkbox">
<input type="date">
<input type="file">
<input type="number">
<input type="radio">
<select>
<input>
<textarea>
簡單的表單範例
表單的驗證也支援 DataAnnotations 不過在此就懶的再記錄一次,請謨拜 Google 大神。
@page "/form-example-1"
@using Microsoft.Extensions.Logging
@inject ILogger<FormExample1> Logger
<EditForm Model="exampleModel" OnValidSubmit="HandleValidSubmit">
<DataAnnotationsValidator />
<ValidationSummary />
<InputText id="name" @bind-Value="exampleModel.Name" />
<ValidationMessage For="@(()=>exampleModel.Name)" />
<button type="submit">Submit</button>
</EditForm>
@code {
private ExampleModel exampleModel = new();
private void HandleValidSubmit()
{
Logger.LogInformation("HandleValidSubmit called");
// Process the valid form
}
}
Last updated