🐥note.

小鳥とMicrosoft <3 なエンジニアの技術Blog📚

Blazor - TodoAppにValidationとNotifyServiceを追加する

こちらの記事の続きです。

blog.piyosi.com

Todoアプリに以下の機能の改造を加えます。

  • 新しいTodoを追加したら画面に通知を表示する(NotifyServiceで別Componentの関数をKick)

  • Todoの内容が空っぽの時は登録できないようValidationを追加する

※子コンポーネントから通知を表示すればこんな回りくどいことしなくて済むのですが、お勉強目的なので目を瞑ります。

Demo

こんな感じになりました。

f:id:piyo_esq:20191016203604g:plain
Demo

成果物

例によってGitHubに公開しています。

今回はsrc\2. NotifyService以下に保存しています。

github.com

NotifyServiceについて

こちらのまんまです。

docs.microsoft.com

NotifierService.cs

関数を登録するNotifyイベントと、登録したイベントを発火させるUpdate関数を持ちます。

using System;
using System.Threading.Tasks;
using BlazorTodo.Data;

namespace BlazorTodo.Service
{
    public class NotifierService
    {
        public async Task Update(Todo todo)
        {
            if (Notify != null)
            {
                await Notify.Invoke(todo);
            }
        }

        public event Func<Todo, Task> Notify;
    }
}

Startup.cs

サービスが使えるよう、StartUp.csConfigureServicesで登録します。

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();
    services.AddServerSideBlazor();
+   services.AddSingleton<NotifierService>();

    services.AddBlazoredToast();    // トースト用
}

Index.razor

indexページでトーストを表示する関数を登録します。

@page "/"
+ @inject NotifierService Notifier
@inject IToastService toastService

<h1>Blazor Todo</h1>

<TodoList Todos="@Todos" />

@code {
    IList<Todo> Todos;
+    string NotifyMessage { get; set; }
    protected override void OnInitialized()
    {
        Todos = new List<Todo>()
            {
                new Todo() { Id = Guid.NewGuid(),  Content = "犬をしまう" },
                new Todo() { Id = Guid.NewGuid(),  Content = "お風呂に水をためる" },
                new Todo() { Id = Guid.NewGuid(),  Content = "水・食料を買い込む" },
                new Todo() { Id = Guid.NewGuid(),  Content = "避難先を確認する" },
            };

+        Notifier.Notify += OnNotify;
    }

+   async Task OnNotify(Todo todo)
+   {
+       await InvokeAsync( () => {
+           toastService.ShowInfo($"新しいTodoItem:{todo.Content}が追加されました!");
+           StateHasChanged();
+       });
+   }

+   void Dispose()
+   {
+       Notifier.Notify -= OnNotify;
+   }
}

TodoList.razor

@using System.Linq;
+ @inject NotifierService Notifier

...

@code {
    [Parameter]
    public IList<Todo> Todos { get; set; }

    async void OnAddNewTodoItem(Todo todo)
    {
        if (Todos != null)
        {
-           Todos.Add(new Todo() { Id = Guid.NewGuid(), Content = newContent });
+           Todos.Add(todo);
+           await Notifier.Update(todo);
            StateHasChanged();
        }
    }

    ...

}

Validation

こちらのまんまです。

docs.microsoft.com

Todo.cs

Model役のクラスに[Required]属性を追加します。

using System;
using System.ComponentModel.DataAnnotations;

namespace BlazorTodo.Data {

    public class Todo {
        public Guid Id { get; set; }

        public bool IsDone { get; set; }

+       [Required(ErrorMessage ="内容を空欄にはできません!")]
        public string Content { get; set; }
    }
}

NewItemEntry.razor

Validateを効かせるためにForm化したのとValidateが通ったとき用のHandleValidSubmit関数を追加します。
Form化したので<input>から@onkeypressはなくします。
※変更点が多いのでdiff表示は止めておきます。

<EditForm class="form-inline" Model="@todoModel" OnValidSubmit="@HandleValidSubmit">
    <div class="row w-100">
        <DataAnnotationsValidator />
        <ValidationSummary />
    </div>

    <div class="form-group row">
        <label class="col-sm-4" for="new-todo-item-content-textbox">New Todo Item</label>
        <input id="new-todo-item-content-textbox" class="form-control col-sm-6" placeholder="Todo Content"
                @bind-value="todoModel.Content" @bind-value:event="oninput"/>
        <button type="Add" class="col-sm-2 btn btn-primary">Submit</button>
    </div>
</EditForm>

@code {
    Todo todoModel = new Todo();

    [Parameter]
    public Action<Todo> OnAddNewTodoItem { get; set; }

    private void HandleValidSubmit()
    {
        AddNewItem();
    }

    void AddNewItem()
    {
        if (OnAddNewTodoItem != null)
        {
            OnAddNewTodoItem(todoModel);
            todoModel = new Todo();
        }
    }
}

備考:通知の表示方法

github.com

のToastを使用しています。

おわり

Validationは今まで通りって感じですね。

NotifyServiceは例によって小さく使わないと破城しそうなので注意が必要ですね。