پیش از ادامهی مثال قسمت قبل، قصد داریم تمام کدهای موجود در فایل Pages\Index.razor را به یک فایل اختصاصی آنها منتقل کرده و مسیریابی و منوی آنرا تکمیل کنیم. به همین جهت در پوشهی Pages، یک پوشهی جدید را به نام LearnBlazor ایجاد کرده و درون آن، فایل خالی BindProp.razor را ایجاد میکنیم. سپس تمام محتوای فایل Pages\Index.razor را cut کرده و به درون فایل جدید Pages\LearnBlazor\BindProp.razor، منتقل و Paste میکنیم.
پس از این تغییرات، در فایل Pages\Index.razor، مهمترین سطر آن، همان اولین سطر تعریف مسیریابی آن خواهد بود و هر محتوای دلخواهی که علاقمند بودید:
@page "/" <h1>Hello, world!</h1>
@page "/bindprop"
<li class="nav-item px-3"> <NavLink class="nav-link" href="bindprop"> <span class="oi oi-list-rich" aria-hidden="true"></span> Bind Properties </NavLink> </li>
نمایش لیست اتاقهای تعریف شده، به همراه ویژگیهای آنها
در قسمت قبل، نمایش ردیفی لیست اتاقهای تعریف شده را مشاهده کردید. در این قسمت میخواهیم هر اتاق تعریف شده را در یک card جداگانه نمایش دهیم. هدف این است که در ابتدا به یک UI متداول شلوغ برسیم و بعد شروع کنیم به Refactoring این UI پیچیده، به کامپوننتهای کوچکتر تشکیل دهندهی آن، جهت مدیریت سادهتر این UI و درک بهتر آن. بنابراین در ابتدا با یک کامپوننت کلی شلوغ، شروع خواهیم کرد.
به همین جهت فایل جدید Pages\LearnBlazor\DemoHotel.razor را برای نمایش لیست اتاقهای موجود اضافه میکنیم. سپس محتوای آنرا به صورت زیر تغییر خواهیم داد:
@page "/demoHotel" <h3>Hotel Rooms</h3> <div class="border p-2 mt-2" style="background-color:azure"> <h2 class="text-info">Rooms List</h2> <div class="row container"> @foreach (var room in Rooms) { <div class="bg-light border p-2 col-5 ml-2"> <h4 class="text-secondary">Room - @room.Id</h4> @room.Name<br /> @room.Price.ToString("c")<br /> <input type="checkbox" @bind-value="room.IsActive" checked="@(room.IsActive?"checked":null)" /> Is Active<br /> <span>This room is @(room.IsActive?"Active": "InActive")</span> @if (room.IsActive) { @foreach (var roomProp in room.RoomProps) { <p>@roomProp.Name - @roomProp.Value</p> } } <input type="button" class="btn btn-danger" value="Delete" /> <input type="button" class="btn btn-success" value="Edit" /> </div> } </div> </div>
- سپس مسیریابی منتهی به این کامپوننت، به آدرس demoHotel/ تنظیم شدهاست. این مسیریابی را در کامپوننت Shared\NavMenu.razor به صورت زیر مورد استفاده قرار خواهیم داد تا مدخل منوی جدیدی برای آن تهیه شود:
<li class="nav-item px-3"> <NavLink class="nav-link" href="demoHotel"> <span class="oi oi-list-rich" aria-hidden="true"></span> Demo Hotel </NavLink> </li>
تبدیل دکمههای حذف و ویرایش هر اتاق به یک کامپوننت جدید
اکنون میخواهیم کامپوننت شلوغ Pages\LearnBlazor\DemoHotel.razor را به چند زیر کامپوننت بشکنیم تا هر کدام وظایف خاص خود را انجام دهند و در نهایت به یک UI قابل درکتر برسیم. برای مثال میخواهیم دکمههای حذف و ویرایش هر اتاق را به یک کامپوننت جدید منتقل کنیم تا هم این UI خلوتتر شود و هم اگر در قسمت دیگری از برنامه نیاز به یک چنین دکمههایی بود، بتوان از آن کامپوننت اختصاصی، استفادهی مجدد کرد.
برای این منظور ابتدا پوشهی جدید Pages\LearnBlazor\LearnBlazorComponents را افزوده و سپس در داخل آن، فایل جدید کامپوننت EditDeleteButton.razor را نیز ایجاد میکنیم. در این فایل جدید در ابتدا کدهای دو دکمهی تعریف شده را از کامپوننت DemoHotel.razor انتخاب و cut کرده و سپس در این فایل جدید paste میکنیم. در این کامپوننت جدید، نیازی به تعریف page@ و مسیریابی آن نیست. به این معنا که این کامپوننت، یک کامپوننت اشتراکی است و routable نیست و قرار است در داخل یک کامپوننت دیگر مورد استفاده قرار گیرد.
بنابراین تا اینجا محتوای کامپوننت EditDeleteButton.razor فقط از دو سطر زیر تشکیل میشود:
<input type="button" class="btn btn-danger" value="Delete" /> <input type="button" class="btn btn-success" value="Edit" />
<BlazorServerSample.Pages.LearnBlazor.LearnBlazorComponents.EditDeleteButton></BlazorServerSample.Pages.LearnBlazor.LearnBlazorComponents.EditDeleteButton>
@using BlazorServerSample.Pages.LearnBlazor.LearnBlazorComponents
اکنون میتوان تعریف مدخل کامپوننت را به صورت زیر خلاصه کرد:
<EditDeleteButton></EditDeleteButton>
ارسال پارامترها به یک کامپوننت
فرض کنید قصد داریم دکمههای ویرایش و حذف را تنها به کاربران ادمین نمایش دهیم. به همین جهت نیاز است بتوان پارامتری مانند IsAdmin را به کامپوننت EditDeleteButton ارسال کرد. برای اینکار کامپوننت Pages\LearnBlazor\LearnBlazorComponents\EditDeleteButton.razor را به صورت زیر ویرایش میکنیم:
@if (IsAdmin) { <input type="button" class="btn btn-danger" value="Delete" /> <input type="button" class="btn btn-success" value="Edit" /> } @code { [Parameter] public bool IsAdmin { get; set; } }
پس از تعریف این پارامتر ورودی، روش استفادهی از آن در کامپوننت DemoHotel به صورت زیر است:
<EditDeleteButton IsAdmin="true"></EditDeleteButton>
انتقال هر اتاق به کامپوننت مجزای خاص خودش
در ادامه میخواهیم محتوای حلقهی foreach (var room in Rooms)@ کامپوننت DemoHotel را به طور کامل cut کرده و در یک کامپوننت جدید paste کنیم تا به حلقهای خواناتر و با مسئولیتهای کمتری برسیم. نگهداری کدهایی که قسمتهای مختلف آن از هم ایزوله شدهاند و دامنهی تغییرات آنها کاملا مشخص و محدود است، در طول زمان بسیار سادهتر از نگهداری کدهای UI ای در هم تنیدهاست.
به همین جهت ابتدا کامپوننت جدید Pages\LearnBlazor\LearnBlazorComponents\IndividualRoom.razor را ایجاد میکنیم و سپس، هر آنچه داخل حلقهی foreach یاد شده قرار دارد را انتخاب و cut کرده و درون این کامپوننت جدید paste میکنیم:
<div class="bg-light border p-2 col-5 offset-1"> <h4 class="text-secondary">Room - @Room.Id</h4> @Room.Name<br /> @Room.Price.ToString("c")<br /> <input type="checkbox" @bind-value="Room.IsActive" checked="@(Room.IsActive?"checked":null)" /> Is Active<br /> <span>This room is @(Room.IsActive?"Active": "InActive")</span> @if (Room.IsActive) { @foreach (var roomProp in Room.RoomProps) { <p>@roomProp.Name - @roomProp.Value</p> } } <EditDeleteButton IsAdmin="true"></EditDeleteButton> </div> @code { [Parameter] public BlazorRoom Room { get; set; } }
پس از این تغییر، کدهای حلقهی foreach کامپوننت DemoHotel.razor به صورت زیر خلاصه میشوند. در اینجا روش ارسال یک شیء را به پارامتر Room نیز مشاهده میکنید (البته ذکر @ در اینجا الزامی نیست و میشد از روش مقدار دهی "Room="room نیز استفاده کرد):
<div class="row container"> @foreach (var room in Rooms) { <IndividualRoom Room="@room"></IndividualRoom> } </div>
یک تمرین: نمایش لیست امکانات رفاهی هتل
پس از نمایش لیست اتاقهای یک هتل، قصد داریم لیست امکانات رفاهی آنرا نیز نمایش دهیم:
مدل این امکانات را به صورت زیر به پوشهی Models برنامه اضافه میکنیم:
namespace BlazorServerSample.Models { public class BlazorAmenity { public int Id { get; set; } public string Name { get; set; } public string Description { get; set; } } }
@code{ List<BlazorAmenity> AmenitiesList = new List<BlazorAmenity>(); // ... protected override void OnInitialized() { base.OnInitialized(); // ... AmenitiesList.Add(new BlazorAmenity { Id = 111, Name = "Gym", Description = "24x7 gym room is available." }); AmenitiesList.Add(new BlazorAmenity { Id = 222, Name = "Swimming Pool", Description = "Pool room is open from 6am to 10pm." }); AmenitiesList.Add(new BlazorAmenity { Id = 333, Name = "Free Brakfast", Description = "Enjoy free breakfast at out hotel." }); } }
اکنون برای نمایش تک تک عناصر این لیست، ابتدا یک کامپوننت منحصر به یک BlazorAmenity را به نام Pages\LearnBlazor\LearnBlazorComponents\IndividualAmenity.razor ایجاد میکنیم با این محتوا:
<div class="bg-light border p-2 col-5 offset-1 mt-2"> <h4 class="text-secondary">Amenity - @Amenity.Id</h4> @Amenity.Name<br /> @Amenity.Description<br /> </div> @code { [Parameter] public BlazorAmenity Amenity { get; set; } }
در آخر پس از تعریف کامپوننت IndividualAmenity.razor، روش استفادهی از آن در کامپوننت DemoHotel به صورت زیر است:
<div class="col-12 mt-4"> <h4 class="text-info">Hotel Amenities</h4> </div> @foreach (var amenity in AmenitiesList) { <IndividualAmenity Amenity="@amenity"></IndividualAmenity> }
کدهای کامل این مطلب را از اینجا میتوانید دریافت کنید: Blazor-5x-Part-05.zip