演習 - テンプレートを作成することによってコンポーネントを再利用する

完了

このピザ会社は、[自分の注文] ページに、過去の注文に関する詳細 (注文したピザや、顧客が注文した時刻など) を顧客に表示したいと考えています。

テンプレートは、Blazing Pizza アプリの [自分の注文] ページの表示と機能を改善するのに役立ちます。 この演習では、[自分の注文] ページで再利用する改ページ位置の自動修正テンプレート コンポーネントを作成します。

改ページ位置の自動修正テンプレート コンポーネントを作成する

新しい Blazor 改ページ位置の自動修正テンプレート コンポーネント ファイルと改ページ位置の自動修正コントロールを作成します。

ファイルを作成してマークアップを追加する

  1. Visual Studio Code の Blazor アプリ プロジェクトで、Components という名前の新しいフォルダーを作成してから、そのフォルダーに PaginationComponent.razor という名前の新しいファイルを作成します。

  2. 新しく作成したテンプレート コンポーネントに、次の Razor マークアップを追加します。

    @typeparam TItem
    
    <div class="container-sm py-4">
        @ItemContent(Items.ElementAt(selectedIndex))
    </div>
    <nav aria-label="Pagination functionality">
        <ul class="pagination pagination-lg justify-content-center">
            <li class="page-item @(previousDisabled ? "disabled" : "")" disabled="@previousDisabled">
                <a class="page-link" @onclick="@(() => SetIndex(0))">
                    <span>⏪</span>
                </a>
            </li>
            <li class="page-item @(previousDisabled ? "disabled" : "")" disabled="@previousDisabled">
                <a class="page-link" @onclick="DecrementIndex"><span>⬅️</span></a>
            </li>
            @foreach ((int index, TItem item) in Items.Select((item, index) => (index, item)))
            {
                var isActive = index == selectedIndex;
                <li class="page-item @(isActive ? "active" :"")">
                    <a class="page-link" @onclick="@(() => SetIndex(index))">
                        @ItemLabel(item)
                    </a>
                </li>
            }
            <li class="page-item @(nextDisabled ? "disabled" : "")" disabled="@nextDisabled">
                <a class="page-link" @onclick="IncrementIndex"><span>➡️</span></a>
            </li>
            <li class="page-item @(nextDisabled ? "disabled" : "")" disabled="@nextDisabled">
                <a class="page-link" @onclick="@(() => SetIndex(Items.Count - 1))">
                    <span>⏩</span>
                </a>
            </li>
        </ul>
    </nav>
    

このマークアップは、ジェネリック型パラメーター TItem を受け取り、選択されている項目を表示するコンテナーを定義し、<nav> 要素を使って改ページ位置の自動修正コントロールを表示します。

このコントロールは、ページ番号である各リスト項目で <ul> 要素を使います。 ページ番号は、パラメーターとして渡される ItemLabel レンダリング フラグメントによって定義されます。 ItemLabel レンダリング フラグメントは、そのテンプレートを使用するコンポーネントで定義されます。

コード ディレクティブを追加する

アクティブな項目を処理する @code ディレクティブを追加します。

@code {
    [Parameter, EditorRequired]
    public required List<TItem> Items { get; set; }

    [Parameter, EditorRequired]
    public required RenderFragment<TItem> ItemContent { get; set; }

    [Parameter, EditorRequired]
    public required Func<TItem, MarkupString> ItemLabel { get; set; }

    int selectedIndex;

    bool previousDisabled => selectedIndex == 0;
    bool nextDisabled => selectedIndex == Items.Count - 1;

    void IncrementIndex() => selectedIndex++;
    void DecrementIndex() => selectedIndex--;
    void SetIndex(int index) => selectedIndex = index;

    protected override void OnInitialized() =>
        selectedIndex = Items.Count - 1;
}

前記のコード ブロックでは、テンプレートを使うために必要なパラメーターが定義されています。

  • Items パラメーターは、表示する TItem 項目の一覧です。
  • ItemContent パラメーターは、選択した項目の内容を表示する方法を定義するレンダリング フラグメントです。
  • ItemLabel パラメーターは、各項目のラベルを表示する方法を定義する関数です。

selectedIndex フィールドは、現在選ばれている項目を追跡します。 IncrementIndexDecrementIndexSetIndex の各メソッドは、選択した項目のインデックスを変更するために使用されます。

OnInitialized メソッドは、最初に選択された項目をリストの最後の項目に設定します。

MyOrders コンポーネントを更新する

次に、テンプレート コンポーネントを使うように [自分の注文] ページを更新します。

  1. エクスプローラーで、[ページ] を展開してから、MyOrders.razor を選びます。

  2. 最後の @inject ディレクティブの後に、@using ディレクティブを追加します。

    @using BlazingPizza.Components
    

    この行により、MyOrder コンポーネントは新しく作成されたコンポーネント テンプレートを使用できます。

  3. <div class="main"> マークアップ内の if / else if / else 論理ブロックで、既存の else 分岐を次のコードに置き換えます。

    else
    {
        <PaginationComponent TItem="OrderWithStatus"
            Items="ordersWithStatus.OrderBy(o => o.Order.CreatedTime).ToList()"
            ItemLabel='item => new($"{item.Order.CreatedTime:ddd, MMM. d, yyyy}")'>
            <ItemContent>
                <div class="list-group-item bg-secondary text-white">
                    <div class="col">
                        <h5>@($"{context.Order.CreatedTime:dddd, MMMM d, yyyy hh:mm tt}")</h5>
                        Items:
                        <strong>@context.Order.Pizzas.Count</strong>
                    </div>
                    <div class="col">
                        Status: <strong>@context.StatusText</strong>
                    </div>
                    @if (@context.StatusText != "Delivered")
                    {
                        <div class="col flex-grow-0">
                            <a href="myorders/@context.Order.OrderId" class="btn btn-success">
                                Track &gt;
                            </a>
                        </div>
                    }
                </div>
                <div class="list-group-item">
                    <div class="col">
                        <OrderReview Order="@context.Order" />
                    </div>
                </div>
            </ItemContent>
        </PaginationComponent>
    }
    

これでコードが PaginationComponent に依存するようになり、OrderWithStatus のジェネリック型、作成日順に並べ替えられた過去の注文の一覧、各項目のラベルを生成する関数が提供されます。 ItemContent レンダリング フラグメントでは、各項目のマークアップが定義されています。

更新をテストする

  1. Visual Studio Code で、F5 キーを押すか、[実行]>[デバッグの開始] を選びます。

  2. アプリで、いくつかの注文を行って、[自分の注文] を選びます。 注文の一覧を含む改ページ位置の自動修正コントロールが表示され、注文を選んで注文の詳細を読み込むことができることを確認します。

    Screenshot of the new order history page.

  3. Shift+F5 キーを押すか、[実行]>[デバッグの停止] を選んで、アプリを停止します。