سلام. این مشکل تو گزارش ساز تلریک و کریستال هم وجود داره. تو کریستال قبل از نمایش میشد گزارش رو تبدیل به pdf کنیم بعد نمایش بدیم که فقط تو این حالت فونتهای سرور نمایش داده میشدند. تو استیمول و تلریک فونتها از قسمت کلاینت خونده میشن. تنها راه ممکن اینه که فیلدها به صورت export as image باشن که اینکار هم زیاد جالب نیست. به نظر من استیمول واسه وب اصلا مناسب نیست و بهتره که تو ویندوز اپلیکیشن ازش استفاده بشه. اگه با تلریک مقایسش بکنین فرقشونو میبینین
نظرات مطالب
پیاده سازی UnitOfWork به وسیله MEF
- بنابراین روی ساختار دیتابیس تاثیر داره. مثالش هم پیوست شد برای آزمایش.
- عمل نکردن خطاهای اعتبارسنجی به بود و نبود یک سری از تعاریف لازم در View هم بر میگرده. توضیح شما یعنی عمل نکردن اعتبارسنجی سمت کلاینت ولی عمل کردن اعتبارسنجی سمت سرور. به ترتیب باید jquery.min.js ، jquery.validate.min.js و jquery.validate.unobtrusive.min.js به View الحاق شده باشند. تنظیمات ClientValidationEnabled و UnobtrusiveJavaScriptEnabled در وب کانفیگ فعال باشند. از متدهایی مانند ValidationMessageFor استفاده شده باشد. این متدها یک سری ویژگیهای خاص unobtrusive رو به عناصر HTML برای شناسایی توسط jquery.validate اضافه میکنند و بدون اینها عملا اعتبارسنجی سمت کاربر رخ نمیده.
در قسمتهای Blazor Server مثال این سری، با روش کار با سرویسهای سمت سرور برنامه، آشنا شدیم. در این نوع برنامهها، فقط کافی است اصل سرویس مدنظر را مستقیما در کامپوننتهای Razor تزریق کرد و سپس میتوان به نحو متداولی با آنها کار کرد؛ اما در برنامههای Blazor WASM خیر! به این نوع برنامههای سمت کلاینت باید همانند برنامههای React ، Angular ، Vue و یا حتی برنامههای مبتنی بر jQuery نگاه کرد. در تمام فناوریهای سمت کلاینت، این درخواستهای Ajax ای هستند که با سرویسهای یک Web API سمت سرور، ارتباط برقرار کرده، اطلاعاتی را به آنها ارسال و یا دریافت میکنند. در برنامههای Blazor WASM نیز باید به همین ترتیب عمل کرد و در اینجا HttpClient دات نت، جایگزین برای مثال jQuery Ajax ، Fetch API و یا XMLHttpRequest استاندارد میشود (البته jQuery Ajax در اصل یک محصور کنندهی استاندارد XMLHttpRequest است که برای اولین بار توسط مایکروسافت در برنامهی Outlook web access معرفی شد).
ایجاد سرویس سمت کلاینت دریافت اطلاعات اتاقها از Web API
در قسمت 24، HotelRoomController را تکمیل کردیم که کار آن، بازگشت اطلاعات تمام اتاقها و یا یک اتاق مشخص به کلاینت است. اکنون میخواهیم در ادامهی قسمت قبل، اگر کاربری بر روی دکمهی Go صفحهی اول رزرو اتاقی کلیک کرد، لیست تمام اتاقهای تعریف شده را به او نمایش دهیم. به همین جهت نیاز به سرویس سمت کلاینتی داریم که بتواند با این Web API endpoint کار کند:
این سرویس را در پوشهی Services پروژهی BlazorWasm.Client ایجاد کردهایم که HotelRoomDTO خود را از پروژهی BlazorServer.Models دریافت میکند. به این ترتیب میتوان مدلی را بین یک Web API سمت سرور و یک سرویس سمت کلاینت، به اشتراک گذاشت. بنابراین پروژهی کلاینت، باید ارجاعی را به پروژهی BlazorServer.Models.csproj نیز داشته باشد.
در ادامه اینترفیس فوق را به صورت زیر پیاده سازی میکنیم:
توضیحات:
- HttpClient یکی از سرویسهای تنظیم شدهی در فایل Program.cs پروژههای سمت کلاینت است. بنابراین میتوان آنرا از طریق تزریق به سازندهی این سرویس، به دست آورد.
- در اینجا برای دریافت اطلاعات JSON دریافتی از سمت سرور و سپس Deserialize خودکار آن به لیستی از DTO تعریف شده، از متد جدید GetFromJsonAsync استفاده شدهاست. این مورد جزو تازههای NET 5x. است.
- در اینجا استفاده از کلاس UriBuilderExt را نیز جهت تشکیل یک URL دارای کوئری استرینگ، مشاهده میکنید. هیچگاه نباید URL نهایی را از طریق جمع زدن اجزای آن به سمت سرور ارسال کرد؛ از این جهت که اجزای آن باید URL-encoded شوند؛ وگرنه در سمت سرور قابلیت پردازش نخواهند داشت. در ادامه تعریف کلاس جدید UriBuilderExt را مشاهده میکنید:
- در اینجا توسط متد AddParameter، کار افزودن کوئری استرینگها به یک Url از پیش مشخص، انجام میشود. کار encoding نهایی به صورت خودکار توسط HttpUtility استاندارد دات نت، انجام خواهد شد.
- تاریخهای ارسالی به سمت سرور را با فرمت yyyy'-'MM'-'dd تبدیل رشته کردیم. این قالب، یکی از قالبهای پذیرفته شدهاست.
- جهت سهولت استفادهی از سرویس فوق و همچنین مدلهای برنامه، فضای نام آنها را به فایل BlazorWasm.Client\_Imports.razor اضافه میکنیم تا در تمام کامپوننتهای برنامهی سمت کلاینت، قابل دسترسی شوند:
- در آخر این سرویس جدید را باید به لیست سرویسهای برنامه معرفی کرد تا قابلیت تزریق در کامپوننتها را پیدا کند:
چند اصلاح جزئی در کنترلرها و سرویسهای سمت سرور
در Url نهایی فوق، دو پارامتر جدید checkInDate و checkOutDate هم وجود دارند. به همین جهت این دو را به اکشن متدهای کنترلر HotelRoom:
و همچنین سرویس سمت سرور IHotelRoomService نیز اضافه میکنیم:
البته فعلا پیاده سازی خاصی ندارند و آنها را در قسمتهای بعد مورد استفاده قرار خواهیم داد.
تنظیمات ویژهی HttpClient برنامهی سمت کلاینت
سرویس ClientHotelRoomService فوق، از HttpClient تزریق شدهی در سازندهی خود استفاده میکند که BaseAddress خود را مطابق تنظیمات ابتدایی برنامه، از HostEnvironment دریافت میکند. در اینجا علاقمندیم تا بجای این تنظیم پیشفرض، فایل جدید appsettings.json را به پوشهی BlazorWasm.Client\wwwroot\appsettings.json کلاینت اضافه کرده (محل قرارگیری آن در برنامههای سمت کلاینت، داخل پوشهی wwwroot است و نه در داخل پوشهی ریشهی اصلی پروژه):
و از این تنظیم جدید به عنوان BaseAddress برنامهی Web API استفاده کنیم که روش آنرا در کدهای ذیل مشاهده میکنید:
تکمیل کامپوننت دریافت لیست تمام اتاقها
در قسمت قبل، کامپوننت خالی HotelRooms.razor را تعریف کردیم. کاربران پس از کلیک بر روی دکمهی Go صفحهی اول، به این کامپوننت هدایت میشوند. اکنون میخواهیم، لیست تمام اتاقها را در این کامپوننت، از Web API برنامه دریافت کنیم:
در اینجا در ابتدا سعی میشود تا HomeModel، از Local Storage که در قسمت قبل آنرا تنظیم کردیم، خوانده شود. سپس با استفاده از متد GetHotelRoomsAsync، لیست اتاقها را از Web API دریافت میکنیم. تمام این عملیات آغازین نیز باید در روال رویدادگران OnInitializedAsync صورت گیرند.
روش اجرای پروژههای Blazor WASM
تا اینجا اگر برنامهی سمت کلاینت را توسط دستور dotnet watch run اجرا کنیم، هرچند صفحهی خالی نمایش لیست اتاقها ظاهر میشود، اما یک خطای fetch error را هم دریافت خواهیم کرد؛ چون نیاز است ابتدا پروژهی Web API را اجرا کرد و سپس پروژهی WASM را.
برای ساده سازی اجرای همزمان این دو پروژه، اگر از ویژوال استودیوی کامل استفاده میکنید، بر روی نام Solution کلیک راست کرده و از منوی ظاهر شده، گزینهی «Set Startup projects» را انتخاب کنید. در صفحه دیالوگ ظاهر شده، گزینهی «multiple startup projects» را انتخاب کرده و از لیست پروژههای موجود، دو پروژهی Web API و WASM را انتخاب کنید و Action مقابل آنها را به Start تنظیم کنید. در اینجا حتی میتوان ترتیب اجرای این پروژهها را هم تغییر داد. در این حالت زمانیکه بر روی دکمهی Run، در ویژوال استودیو کلیک میکنید، هر دو پروژه را با هم برای شما اجرا خواهد کرد.
نکتهی مهم! در این حالت هم برنامهی کلاینت نمیتواند با برنامهی Web API ارتباط برقرار کند! چون شماره پورت iisExpress درج شدهی در فایل appsettings.json آن، باید به شماره sslPort مندرج در فایل Properties\launchSettings.json پروژهی Web API تغییر داده شود که برای نمونه در اینجا این عدد 44314 است:
و یا اگر میخواهید پروژه را از طریق NET Core CLI. با اجرای دستور dotnet watch run اجرا کنید ... به صورت پیشفرض نمیشود! چون برای اینکار باید به پوشهی ریشهی پروژههای Web API و WASM وارد شد و دوبار دستور یاد شده را به صورت مجزا اجرا کرد. در این حالت، هر دو پروژه، بر روی پورت پیشفرض 5001 اجرا میشوند. روش تغییر این پورت، مراجعه به فایل Properties\launchSettings.json این پروژهها است. برای مثال همان پورت پیشفرض 5001 را که در فایل appsettings.json انتخاب کردیم، ثابت نگه میداریم. یعنی فایل launchSettings.json پروژهی Web API را ویرایش نمیکنیم. اما این پورت را در پروژهی کلاینت برای مثال به عدد 5002 تغییر میدهیم تا برنامهی کلاینت، بر روی پورت پیشفرض برنامهی Web API اجرا نشود:
کدهای کامل این مطلب را از اینجا میتوانید دریافت کنید: Blazor-5x-Part-27.zip
ایجاد سرویس سمت کلاینت دریافت اطلاعات اتاقها از Web API
در قسمت 24، HotelRoomController را تکمیل کردیم که کار آن، بازگشت اطلاعات تمام اتاقها و یا یک اتاق مشخص به کلاینت است. اکنون میخواهیم در ادامهی قسمت قبل، اگر کاربری بر روی دکمهی Go صفحهی اول رزرو اتاقی کلیک کرد، لیست تمام اتاقهای تعریف شده را به او نمایش دهیم. به همین جهت نیاز به سرویس سمت کلاینتی داریم که بتواند با این Web API endpoint کار کند:
namespace BlazorWasm.Client.Services { public interface IClientHotelRoomService { public Task<IEnumerable<HotelRoomDTO>> GetHotelRoomsAsync(DateTime checkInDate, DateTime checkOutDate); public Task<HotelRoomDTO> GetHotelRoomDetailsAsync(int roomId, DateTime checkInDate, DateTime checkOutDate); } }
در ادامه اینترفیس فوق را به صورت زیر پیاده سازی میکنیم:
namespace BlazorWasm.Client.Services { public class ClientHotelRoomService : IClientHotelRoomService { private readonly HttpClient _httpClient; public ClientHotelRoomService(HttpClient httpClient) { _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient)); } public Task<HotelRoomDTO> GetHotelRoomDetailsAsync(int roomId, DateTime checkInDate, DateTime checkOutDate) { throw new NotImplementedException(); } public Task<IEnumerable<HotelRoomDTO>> GetHotelRoomsAsync(DateTime checkInDate, DateTime checkOutDate) { // How to url-encode query-string parameters properly var uri = new UriBuilderExt(new Uri(_httpClient.BaseAddress, "/api/hotelroom")) .AddParameter("checkInDate", $"{checkInDate:yyyy'-'MM'-'dd}") .AddParameter("checkOutDate", $"{checkOutDate:yyyy'-'MM'-'dd}") .Uri; return _httpClient.GetFromJsonAsync<IEnumerable<HotelRoomDTO>>(uri); } } }
- HttpClient یکی از سرویسهای تنظیم شدهی در فایل Program.cs پروژههای سمت کلاینت است. بنابراین میتوان آنرا از طریق تزریق به سازندهی این سرویس، به دست آورد.
- در اینجا برای دریافت اطلاعات JSON دریافتی از سمت سرور و سپس Deserialize خودکار آن به لیستی از DTO تعریف شده، از متد جدید GetFromJsonAsync استفاده شدهاست. این مورد جزو تازههای NET 5x. است.
- در اینجا استفاده از کلاس UriBuilderExt را نیز جهت تشکیل یک URL دارای کوئری استرینگ، مشاهده میکنید. هیچگاه نباید URL نهایی را از طریق جمع زدن اجزای آن به سمت سرور ارسال کرد؛ از این جهت که اجزای آن باید URL-encoded شوند؛ وگرنه در سمت سرور قابلیت پردازش نخواهند داشت. در ادامه تعریف کلاس جدید UriBuilderExt را مشاهده میکنید:
using System; using System.Collections.Generic; using System.Net.Http; using System.Net.Http.Json; using System.Threading.Tasks; using BlazorServer.Models; using BlazorWasm.Client.Utils; using System; using System.Collections.Specialized; using System.Web; namespace BlazorWasm.Client.Utils { public class UriBuilderExt { private readonly NameValueCollection _collection; private readonly UriBuilder _builder; public UriBuilderExt(Uri uri) { _builder = new UriBuilder(uri); _collection = HttpUtility.ParseQueryString(string.Empty); } public UriBuilderExt AddParameter(string key, string value) { _collection.Add(key, value); return this; } public Uri Uri { get { _builder.Query = _collection.ToString(); return _builder.Uri; } } } }
- تاریخهای ارسالی به سمت سرور را با فرمت yyyy'-'MM'-'dd تبدیل رشته کردیم. این قالب، یکی از قالبهای پذیرفته شدهاست.
- جهت سهولت استفادهی از سرویس فوق و همچنین مدلهای برنامه، فضای نام آنها را به فایل BlazorWasm.Client\_Imports.razor اضافه میکنیم تا در تمام کامپوننتهای برنامهی سمت کلاینت، قابل دسترسی شوند:
@using BlazorWasm.Client.Services @using BlazorServer.Models
namespace BlazorWasm.Client { public class Program { public static async Task Main(string[] args) { var builder = WebAssemblyHostBuilder.CreateDefault(args); // ... builder.Services.AddScoped<IClientHotelRoomService, ClientHotelRoomService>(); // ... } } }
چند اصلاح جزئی در کنترلرها و سرویسهای سمت سرور
در Url نهایی فوق، دو پارامتر جدید checkInDate و checkOutDate هم وجود دارند. به همین جهت این دو را به اکشن متدهای کنترلر HotelRoom:
namespace BlazorWasm.WebApi.Controllers { [Route("api/[controller]")] [ApiController] public class HotelRoomController : ControllerBase { // ... [HttpGet] public async Task<IActionResult> GetHotelRooms(DateTime? checkInDate, DateTime? checkOutDate) { // ... } [HttpGet("{roomId}")] public async Task<IActionResult> GetHotelRoom(int? roomId, DateTime? checkInDate, DateTime? checkOutDate) { // ... } } }
namespace BlazorServer.Services { public interface IHotelRoomService : IDisposable { Task<List<HotelRoomDTO>> GetAllHotelRoomsAsync(DateTime? checkInDate, DateTime? checkOutDate); Task<HotelRoomDTO> GetHotelRoomAsync(int roomId, DateTime? checkInDate, DateTime? checkOutDate); // ... } }
تنظیمات ویژهی HttpClient برنامهی سمت کلاینت
سرویس ClientHotelRoomService فوق، از HttpClient تزریق شدهی در سازندهی خود استفاده میکند که BaseAddress خود را مطابق تنظیمات ابتدایی برنامه، از HostEnvironment دریافت میکند. در اینجا علاقمندیم تا بجای این تنظیم پیشفرض، فایل جدید appsettings.json را به پوشهی BlazorWasm.Client\wwwroot\appsettings.json کلاینت اضافه کرده (محل قرارگیری آن در برنامههای سمت کلاینت، داخل پوشهی wwwroot است و نه در داخل پوشهی ریشهی اصلی پروژه):
{ "BaseAPIUrl": "https://localhost:5001/" }
namespace BlazorWasm.Client { public class Program { public static async Task Main(string[] args) { var builder = WebAssemblyHostBuilder.CreateDefault(args); // ... // builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.Configuration.GetValue<string>("BaseAPIUrl")) }); // ... } } }
تکمیل کامپوننت دریافت لیست تمام اتاقها
در قسمت قبل، کامپوننت خالی HotelRooms.razor را تعریف کردیم. کاربران پس از کلیک بر روی دکمهی Go صفحهی اول، به این کامپوننت هدایت میشوند. اکنون میخواهیم، لیست تمام اتاقها را در این کامپوننت، از Web API برنامه دریافت کنیم:
@page "/hotel/rooms" @inject ILocalStorageService LocalStorage @inject IJSRuntime JsRuntime @inject IClientHotelRoomService HotelRoomService <h3>HotelRooms</h3> @code { HomeVM HomeModel = new HomeVM(); IEnumerable<HotelRoomDTO> Rooms = new List<HotelRoomDTO>(); protected override async Task OnInitializedAsync() { try { var model = await LocalStorage.GetItemAsync<HomeVM>(ConstantKeys.LocalInitialBooking); if (model is not null) { HomeModel = model; } else { HomeModel.NoOfNights = 1; } await LoadRooms(); } catch (Exception e) { await JsRuntime.ToastrError(e.Message); } } private async Task LoadRooms() { Rooms = await HotelRoomService.GetHotelRoomsAsync(HomeModel.StartDate, HomeModel.EndDate); } }
روش اجرای پروژههای Blazor WASM
تا اینجا اگر برنامهی سمت کلاینت را توسط دستور dotnet watch run اجرا کنیم، هرچند صفحهی خالی نمایش لیست اتاقها ظاهر میشود، اما یک خطای fetch error را هم دریافت خواهیم کرد؛ چون نیاز است ابتدا پروژهی Web API را اجرا کرد و سپس پروژهی WASM را.
برای ساده سازی اجرای همزمان این دو پروژه، اگر از ویژوال استودیوی کامل استفاده میکنید، بر روی نام Solution کلیک راست کرده و از منوی ظاهر شده، گزینهی «Set Startup projects» را انتخاب کنید. در صفحه دیالوگ ظاهر شده، گزینهی «multiple startup projects» را انتخاب کرده و از لیست پروژههای موجود، دو پروژهی Web API و WASM را انتخاب کنید و Action مقابل آنها را به Start تنظیم کنید. در اینجا حتی میتوان ترتیب اجرای این پروژهها را هم تغییر داد. در این حالت زمانیکه بر روی دکمهی Run، در ویژوال استودیو کلیک میکنید، هر دو پروژه را با هم برای شما اجرا خواهد کرد.
نکتهی مهم! در این حالت هم برنامهی کلاینت نمیتواند با برنامهی Web API ارتباط برقرار کند! چون شماره پورت iisExpress درج شدهی در فایل appsettings.json آن، باید به شماره sslPort مندرج در فایل Properties\launchSettings.json پروژهی Web API تغییر داده شود که برای نمونه در اینجا این عدد 44314 است:
{ "iisSettings": { "iisExpress": { "applicationUrl": "http://localhost:62930", "sslPort": 44314 } } }
{ "BlazorWasm.Client": { "applicationUrl": "https://localhost:5002;http://localhost:5003", } }
کدهای کامل این مطلب را از اینجا میتوانید دریافت کنید: Blazor-5x-Part-27.zip
«اما اینکه چند قسمت بدون هیچ کلیکی با سرعت مناسب و غیر همزمان بالا بیاره باید چه کارکنم؟»
زمانیکه از قطعه کد زیر استفاده میشود، یعنی از jQuery Document ready استفاده شدهاست:
کدهای داخل آن بلافاصله و به صورت خودکار پس از آماده شدن DOM یا document object model، اجرا خواهند شد.
اطلاعات بیشتر: «آموزش (jQuery) جی کوئری 1#»
زمانیکه از قطعه کد زیر استفاده میشود، یعنی از jQuery Document ready استفاده شدهاست:
<script type="text/javascript"> $(function () { //کدهای خود اجرا شونده در اینجا }); </script>
اطلاعات بیشتر: «آموزش (jQuery) جی کوئری 1#»
روش عدم ارسال فرم در صورت شکست اعتبارسنجی:
<script type="text/javascript"> $(document).ready(function () { $("form").submit(function () { $(this).validate(); if (!$(this).valid()) { console.log("validation error"); //note: here return false will stop the submit return false; } }); }); </script>
نظرات مطالب
معرفی Kendo UI
- کد نهایی قسمت اول در اینجا ارسال شده و فقط در آن از این یک سطر، در آخر کمک گرفته شدهاست:
- مواردی که در انتهای بحث ذکر شدند، قابلیت ترکیب ندارند؛ یعنی نمیتوانید تمام اسکریپتهای Kendo UI را به نحوی که ذکر شد در کنار هم قرار دهید. هدف بیشتر طرح گروه بندی آنها بود. به همین جهت فقط از kendo.all استفاده کنید.
<script src="js/kendo.all.min.js" type="text/javascript"></script>
نظرات مطالب
ASP.NET MVC #21
$.validator.unobtrusive.parse باید در جایی فراخوانی شود که کار load اولیه را انجام داده:
اگر این کد را در partial view ایی که قرار است load شود قرار دادید، در آنجا فقط بنویسید:
@Ajax.ActionLink("Test", "action", new AjaxOptions { HttpMethod = "POST", InsertionMode = InsertionMode.Replace, UpdateTargetId = "UserDiv", OnSuccess="$.validator.unobtrusive.parse('#my_form_id');" } )
<script type="text/javascript"> $.validator.unobtrusive.parse("#my_frm_id"); </script>
نظرات اشتراکها
چرا باید امروز node.js را یاد بگیریم
node.js فناوری سمت سرور است ولی angularjs سمت کلاینت. مقایسشون بی ربط است.
وقتی پروژه انگیولاریتان کمی گسترش پیدا کند، تعداد زیادی فایل شامل کنترلرها، سرویسها، دایرکتیوها و ... خواهید داشت. واضح است که همه این اجزا همراه با هم مورد نیاز نیستند و برای افزایش سرعت بارگذاری سایت و صرفه جویی در مصرف پهنای باند بهتر است هرکدام از آنها را در هنگام نیاز بارگذاری کنیم. این یعنی همان lazy loading خودمان!
در AngularJS امکانی برای lazy loading فایلها پیشبینی نشده است، پس باید از ابزارهای دیگری که این امکان را فراهم میکنند استفاده کرد. من در ادامه از Script.js برای این کار استفاده خواهم کرد، ولی شما میتوانید از هر کتابخانه دیگری استفاده کنید.
اما مسئله دیگری که پیش از lazy loading فایلها باید تکلیفش را معلوم کنیم، این است که چطور میتوانیم اجزایی را به ماژولی که قبلا راهاندازی (bootstrap) شده اضافه کنیم. اگر بخواهیم برای مثال کنترلری را در یک فایل مجزا تعریف کنیم، باید آن را به شکلی در ماژول برنامهمان ثبت کنیم. فرض کنید این کار را به این ترتیب انجام دهیم:
angular.module('app').controller('SomeLazyController', function($scope) { $scope.key = '...'; });
Error: Argument ‘SomeLazyController’ is not a function, got undefined
// Registering a controller after app bootstrap $controllerProvider.register('SomeLazyController', function($scope) { $scope.key = '...'; }); // Registering a directive after app bootstrap $compileProvider.directive('SomeLazyDirective', function() { return { restrict: 'A', templateUrl: 'templates/some-lazy-directive.html' } }) // etc
اما نکتهای که درباره providerها وجود دارد این است که آنها تنها در روال config یک ماژول در دسترس هستند. بنا بر این برای دسترسی به آنها پس از اجرای این روال، ارجاعی به آنها را باید نگهداری کنیم:
(function () { app = angular.module("app", []); app.config([ '$controllerProvider', '$compileProvider', '$filterProvider', '$provide', function ($controllerProvider, $compileProvider, $filterProvider, $provide) { //برای رجیستر کردن غیر همروند اجزای انگیولاری در آینده app.lazy = { controller: $controllerProvider.register, directive: $compileProvider.directive, filter: $filterProvider.register, factory: $provide.factory, service: $provide.service }; }]); })();
angular.module('app').lazy.controller('SomeLazyController', function($scope) { $scope.key = '...'; });
$stateProvider .state('state1', { url: '/state1', template: '<div>{{st1Ctrl.msg}}</div>', controller: 'state1Controller as st1Ctrl', resolve: { fileDeps: ['$q', '$rootScope', function ($q, $rootScope) { var deferred = $q.defer(); var deps = [ 'app/messageService.js', 'app/state1Controller.js']; $script(deps, function () { $rootScope.$apply(function () { deferred.resolve(); }); }); return deferred.promise; }] } }) .state('state2', { url: '/state2', template: '<div>{{st2Ctrl.msg}}</div>', controller: 'state2Controller as st2Ctrl', resolve: { fileDeps: ['$q', '$rootScope', function ($q, $rootScope) { var deferred = $q.defer(); var deps = [ 'app/messageService.js', 'app/state2Controller.js']; $script(deps, function () { $rootScope.$apply(function () { deferred.resolve(); }); }); return deferred.promise; }] } }); }]);
کنترلر state1Controller که در فایلی با همین نام پیادهسازی شده است تنها در مسیر state1/ مورد نیاز است، و state2Controller تنها در مسیر state2/ لازم است بارگذاری شود. هردوی این کنترلرها به messageService وابستگی دارند که در messageService.js پیاده سازی شده است (همانطور که در این مطلب اشاره شده میتوانیم یک حالت انتزاعی به عنوان پدر دو حالت موجود تعریف کرده و وابستگی مشترک را به آن منتقل کنیم).
برای بارگذاری فایلهای مورد نیاز در ابتدای کار و راه اندازی اولیه برنامه هم میتوان به این ترتیب عمل کرد:
<script type="text/javascript"> // ----Script.js---- !function (a, b, c) { function t(a, c) { var e = b.createElement("script"), f = j; e.onload = e.onerror = e[o] = function () { e[m] && !/^c|loade/.test(e[m]) || f || (e.onload = e[o] = null, f = 1, c()) }, e.async = 1, e.src = a, d.insertBefore(e, d.firstChild) } function q(a, b) { p(a, function (a) { return !b(a) }) } var d = b.getElementsByTagName("head")[0], e = {}, f = {}, g = {}, h = {}, i = "string", j = !1, k = "push", l = "DOMContentLoaded", m = "readyState", n = "addEventListener", o = "onreadystatechange", p = function (a, b) { for (var c = 0, d = a.length; c < d; ++c) if (!b(a[c])) return j; return 1 }; !b[m] && b[n] && (b[n](l, function r() { b.removeEventListener(l, r, j), b[m] = "complete" }, j), b[m] = "loading"); var s = function (a, b, d) { function o() { if (!--m) { e[l] = 1, j && j(); for (var a in g) p(a.split("|"), n) && !q(g[a], n) && (g[a] = []) } } function n(a) { return a.call ? a() : e[a] } a = a[k] ? a : [a]; var i = b && b.call, j = i ? b : d, l = i ? a.join("") : b, m = a.length; c(function () { q(a, function (a) { h[a] ? (l && (f[l] = 1), o()) : (h[a] = 1, l && (f[l] = 1), t(s.path ? s.path + a + ".js" : a, o)) }) }, 0); return s }; s.get = t, s.ready = function (a, b, c) { a = a[k] ? a : [a]; var d = []; !q(a, function (a) { e[a] || d[k](a) }) && p(a, function (a) { return e[a] }) ? b() : !function (a) { g[a] = g[a] || [], g[a][k](b), c && c(d) }(a.join("|")); return s }; var u = a.$script; s.noConflict = function () { a.$script = u; return this }, typeof module != "undefined" && module.exports ? module.exports = s : a.$script = s }(this, document, setTimeout) $script('Scripts/angular.js', function () { $script('Scripts/angular-ui-router.js', function () { $script('app/app.js', function () { angular.bootstrap(document, ['app']); }); }); }); </script>
توجه داشته باشید که لازم نیست بارگذاری فایلها حتما یکی پس از دیگری باشد. ترتیب بارگذاری فایلها تنها در آنهایی که وابستگی به هم دارند باید رعایت شود. همچنین، میتوانید همه فایلهای مورد نیاز در این مرحله را Bundle کنید.
از اینجا میتوانید پروژه بسیار سادهای که در آن lazy loading پیاده شده است را دانلود کرده و مطالب توضیح داده شده را مشاهده کنید.
اشتراکها
پروژه Help Desk در ابعاد کوچک
یک پروژه اپن سورس مبتنی بر Vue.js و ASP.NET MVC Core
هدف پروژه: یک میزکار خدمات رایانه ای در ابعاد کوچک