بررسی تازههای Angular CLI 7.0
پشتیبانی بهتر WebStorm از Angular
بررسی تغییرات Angular CLI 6.1
ng2-ckeditor-wtak9h در انگولار5
آیا به یادگیری یا ادامهی استفاده از AngularJS خواهید پرداخت؟
Ember هم همینطور. قدرتمند هستش ولی این فریم ورک هم داره مثل آنگولار جون میگیره و مطمئن هستم که جنگ سختی بین این دوتا رو شاهد خواهیم بود.
مسیریابی در +Angular 2
عموما از مسیریابی جهت حرکت بین Viewهای مختلف برنامه استفاده میشود، اما کارهای بیشتری را نیز میتوان با آن انجام داد؛ مانند ارسال اطلاعات، به مسیریابیها، پیش بارگذاری اطلاعات، جهت نمایش در Viewها، گروه بندی و محافظت از مسیریابیها، پویانمایی و انیمیشن و همچنین بهبود کارآیی، با بارگذاری async مسیرهای مختلف.
کار سیستم مسیریاب +Angular 2 زمانی شروع میشود که تغییری را در آدرس درخواستی از برنامه مشاهده میکند؛ یا از طریق درخواست آدرسی توسط مرورگر و یا هدایت به قسمتی خاص، از طریق کدنویسی. سپس مسیریاب به آرایهی تنظیم شدهی مسیرهای سیستم مراجعه میکند تا بتواند تطابقی را بین آدرس درخواستی و یکی از کلیدهای تنظیم شدهی در آن پیدا کند. در این حالت اگر تطابقی یافت نشود، کارمسیریابی خاتمه خواهد یافت. در غیراینصورت کار ادامه یافته و سپس مسیریاب، محافظهای مسیر درخواستی را بررسی میکند تا مشخص شود که آیا کاربر مجاز به هدایت به این قسمت خاص از برنامه هست یا خیر؟ در صورت مثبت بودن پاسخ، مرحلهی بعد، پیش بارگذاری اطلاعات درخواستی جهت نمایش View مرتبط است. در ادامه کامپوننت متناظر با مسیریابی فعالسازی میشود. سپس قالب این کامپوننت را در قسمتی که توسط router-outlet مشخص میگردد، جایگذاری کرده و نمایش میدهد.
تعریف مسیر پایه یا Base path
اولین مرحلهی کار با سیستم مسیریابی +Angular 2، تعریف یک base path است. مسیرپایه، به زیرپوشهای اشاره میکند که برنامهی ما در آن قرار گرفتهاست:
www.mysite.com/myapp
مسیریاب از این مسیرپایه جهت ساخت آدرسهای مسیریابی استفاده میکند. مقدار آن نیز به صورت ذیل در فایل index.html برنامه، درست پس از تگ head تعیین میگردد:
<!DOCTYPE html> <html> <head> <base href="/">
<base href="/myapp/">
تعیین مسیرپایه جهت ارائهی نهایی
استفاده از مسیر پایه / برای حالت توسعه و همچنین زمانیکه برنامهی نهایی شما در ریشهی سایت توزیع میشود، بسیار مناسب است. اما اگر برای حالت توسعه از مقدار / و برای حالت توزیع از مقدار /myapp/ بخواهید استفاده کنید، مدام نیاز خواهید داشت تا فایل index.html نهایی سایت را ویرایش کنید. برای این منظور Angular CLI دارای پرچمی است به نام base-href:
> ng build --base-href /myapp/
حالت پیش فرض تولید برنامههای Angular توسط Angular CLI، تنظیم مسیرپایه در فایل src\index.html به صورت خودکار به / میباشد.
تعریف مسیریاب Angular
مسیریاب Angular در ماژولی به نام RouterModule قرار گرفتهاست و باید در ابتدای کار import شود. این ماژول شامل سرویسی است جهت هدایت کاربران به صفحات دیگر و مدیریت URLها، تنظیماتی برای تعریف جزئیات مسیریابیها و تعدادی دایرکتیو که برای فعالسازی و نمایش مسیرها از آنها استفاده میشود. برای مثال دایرکتیو RouterLink آن یک المان قابل کلیک HTML را به مسیر و کامپوننتی خاص در برنامه متصل میکند. RouterLinkActive، شیوهنامهها را به لینک فعال انتساب میدهد و RouterOutlet محل نمایش قالب کامپوننت فعال شده را مشخص میکند.
یک مثال: در ادامه، یک پروژهی جدید مبتنی بر Angular CLI را به نام angular-routing-lab به همراه تنظیمات ابتدایی مسیریابی آن ایجاد میکنیم:
> ng new angular-routing-lab --routing
> npm install bootstrap --save
"apps": [ { "styles": [ "../node_modules/bootstrap/dist/css/bootstrap.min.css", "styles.css" ],
در ادامه اگر به فایل src\app\app-routing.module.ts مراجعه کنید، یک چنین محتوایی را خواهید یافت:
import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; const routes: Routes = [ { path: '', children: [] } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }
میتوان این قسمت را خلاصه کرد و فایل app-routing.module.ts را نیز حذف کرد و سپس import لازم و تعریف ماژول آنرا به ماژول آغازین برنامه یا همان src\app\app.module.ts نیز منتقل کرد. اما پس از مدتی تنظیمات مسیریابی آن، فایل ماژول اصلی برنامه را بیش از اندازه شلوغ خواهند کرد. بنابراین Angular-CLI تصمیم به ایجاد یک ماژول مستقل را برای تعریف تنظیمات مسیریابی برنامه گرفتهاست. سپس تعریف آن را به فایل src\app\app.module.ts به صورت خودکار اضافه میکند:
import { AppRoutingModule } from './app-routing.module'; @NgModule({ imports: [ AppRoutingModule ],
اگر به قسمت import مربوط به NgModule فایل src\app\app-routing.module.ts دقت کنید، این ماژول به همراه متد forRoot معرفی شدهاست.
@NgModule({ imports: [RouterModule.forRoot(routes)],
الف) forRoot
- کار آن تعریف دایرکتیوهای مسیریابی، مدیریت تنظیمات مسیریابی و ثبت سرویس مسیریابی است.
- نکتهی مهم اینجا است که متد forRoot تنها یکبار باید در طول عمر یک برنامه تعریف شود.
- این متد آرایهای از تنظیمات مسیریابیهای تعریف شده را دریافت میکند.
ب) forChild
- کار آن تعریف دایرکتیوهای مسیریابی و مدیریت تنظیمات مسیریابی است؛ اما سرویس مسیریابی را مجددا ثبت نمیکند.
- از این متد در جهت تعریف مسیریابیهای ماژولهای ویژگیهای مختلف برنامه و نظم بخشیدن به آنها استفاده میشود.
بنابراین زمانیکه از forRoot استفاده میشود، سرویس مسیریابی تنها یکبار ثبت خواهد شد و تنها یک وهله از آن موجود خواهد بود. در ادامه هر کدام از ماژولهای دیگر برنامه میتوانند forChild خاص خودشان را داشته باشند.
اکنون تمام کامپوننتهای قید شدهی در قسمت declaration، امکان دسترسی به دایرکتیوهای مسیریابی را پیدا میکنند. همچنین از آنجائیکه AppRoutingModule به همراه متد forRoot است، سرویس مسیریابی نیز در کل برنامه قابل دسترسی است.
تنظیمات اولیه مسیریابی برنامه
آرایهی const routes: Routes فایل src\app\app-routing.module.ts در ابتدای کار خالی است. در اینجا کار تعریف URL segments و سپس اتصال آنها به کامپوننتهای متناظری جهت فعالسازی و نمایش قالب آنها صورت میگیرد. این نمایش نیز در محل router-outlet تعریف شدهی در فایل src\app\app.component.html انجام میشود:
<h1> {{title}} </h1> <router-outlet></router-outlet>
در ادامه برای تکمیل مثال جاری، دو کامپوننت جدید خوشآمد گویی و همچنین یافتن نشدن مسیرها را به برنامه اضافه میکنیم:
>ng g c welcome >ng g c PageNotFound
@NgModule({ declarations: [ AppComponent, WelcomeComponent, PageNotFoundComponent ],
سپس فایل src\app\app-routing.module.ts را به نحو ذیل تکمیل نمائید:
import { PageNotFoundComponent } from './page-not-found/page-not-found.component'; import { WelcomeComponent } from './welcome/welcome.component'; import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; const routes: Routes = [ { path: 'welcome', component: WelcomeComponent }, { path: '', redirectTo: 'welcome', pathMatch: 'full' }, { path: '**', component: PageNotFoundComponent }, ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }
یک نکته: افزونهی auto import، کار تعریف کامپوننتها را در VSCode بسیار ساده میکند و امکان تشکیل خودکار قسمت import را با ارائهی یک intellisense به همراه دارد.
سپس کار تکمیل آرایهی Routes انجام شدهاست. همانطور که مشاهده میکنید، این آرایه متشکل است از اشیایی که به همراه خاصیت path و سایر پارامترهای مورد نیاز هستند.
کار خاصیت path، تعیین URL segment متناظری است که این مسیریابی را فعال میکند. برای مثال اولین شیء تعریف شده با آدرسهایی مانند www.mysite.com/welcome متناظر است.
{ path: 'welcome', component: WelcomeComponent },
چند نکته:
- در حین تعریف مقدار خاصیت path، هیچ / آغاز کنندهای تعریف نشدهاست.
- مقدار خاصیت path، حساس به کوچکی و بزرگی حروف است.
- WelcomeComponent تعریف شده، یک رشته نیست و ارجاعی را به کامپوننت مرتبط دارد. به همین جهت نیاز به import statement ابتدایی را دارد و وجود آن توسط کامپایلر بررسی میشود.
تعیین مسیریابی پیش فرض سایت
اما زمانیکه برنامه برای بار اول بارگذاری میشود، چطور؟ در این حالت هیچ URL segment ایی وجود ندارد. بنابراین برای تنظیم مسیرپیش فرض سایت، خاصیت path، به یک رشتهی خالی همانند دومین شیء تنظیمات مسیریابی، تنظیم میشود:
{ path: '', redirectTo: 'welcome', pathMatch: 'full' },
مدیریت مسیریابی آدرسهای ناموجود در سایت
تنظیم سومی را نیز در اینجا مشاهده میکنید:
{ path: '**', component: PageNotFoundComponent },
یک نکته: ترتیب مسیریابیها در آرایهی تعریف آنها اهمیت دارد. در اینجا از استراتژی «اولین تطابق یافته، برنده خواهد بود» استفاده میشود. بنابراین تنظیم ** باید در انتهای لیست ذکر شود؛ در غیراینصورت هیچکدام از مسیریابیهای تعریف شدهی پس از آن پردازش نخواهند شد.
مدیریت تغییرات آدرسهای برنامه
در طول عمر برنامه ممکن است نیاز به تغییر آدرسهای برنامه باشد. برای مثال بجای مسیر welcome مسیر home نمایش داده شود:
const routes: Routes = [ { path: 'home', component: WelcomeComponent }, { path: 'welcome', redirectTo: 'home', pathMatch: 'full' }, { path: '', redirectTo: 'welcome', pathMatch: 'full' }, { path: '**', component: PageNotFoundComponent } ];
نکته: redirectToها قابلیت تعریف زنجیرهای را ندارند. به این معنا که اگر ریشهی سایت درخواست شود، ابتدا به مسیر welcome هدایت خواهیم شد. مسیر welcome هم یک redirectTo دیگر به مسیر home را دارد. اما در اینجا کار به این redirectTo دوم نخواهد رسید و این پردازش، زنجیرهای نیست. بنابراین مسیریابی پیشفرض را نیز باید ویرایش کرد و به home تغییر داد:
const routes: Routes = [ { path: 'home', component: WelcomeComponent }, { path: 'welcome', redirectTo: 'home', pathMatch: 'full' }, { path: '', redirectTo: 'home', pathMatch: 'full' }, { path: '**', component: PageNotFoundComponent } ];
نکته: redirectToها میتوانند local و یا absolute باشند. تعریف محلی آنها مانند ذکر home و welcome در اینجا است و تنها سبب تغییر یک URL segment میشود. اما اگر در ابتدای مقادیر redirectToها یک / قرار دهیم، به معنای تعریف یک مسیر مطلق است و کل URL را جایگزین میکند.
تعیین محل نمایش قالبهای کامپوننتها
زمانیکه یک کامپوننت فعالسازی میشود، قالب آن در router-outlet نمایش داده خواهد شد. برای این منظور فایل src\app\app.component.html را گشوده و به نحو ذیل تغییر دهید:
<nav class="navbar navbar-default"> <div class="container-fluid"> <a class="navbar-brand">{{title}}</a> <ul class="nav navbar-nav"> <li> <a [routerLink]="['/home']">Home</a> </li> </ul> </div> </nav> <div class="container"> <router-outlet></router-outlet> </div>
یک نکته: چون کامپوننت welcome از طریق مسیریابی نمایش داده میشود و دیگر به صورت مستقیم با درج تگ selector آن در صفحه فعالسازی نخواهد شد، میتوان به تعریف کامپوننت آن مراجعه کرده و selector آنرا حذف کرد.
@Component({ //selector: 'app-welcome', templateUrl: './welcome.component.html', styleUrls: ['./welcome.component.css'] })
تا اینجا اگر دستور ng serve -o را صادر کنیم (کار build درون حافظهای جهت محیط توسعه و نمایش خودکار برنامه در مرورگر)، چنین خروجی در مرورگر نمایان خواهد شد:
اگر به آدرس تنظیم شدهی در مرورگر دقت کنید، http://localhost:4200/home آدرسی است که در ابتدای نمایش سایت نمایان خواهد شد. علت آن نیز به تنظیم مسیریابی پیش فرض سایت برمیگردد.
و اگر یک مسیر غیرموجود را درخواست دهیم، قالب کامپوننت PageNotFound ظاهر میشود:
هدایت کاربران به قسمتهای مختلف برنامه
کاربران را میتوان به روشهای مختلفی به قسمتهای گوناگون برنامه هدایت کرد؛ برای مثال با کلیک بر روی المانهای قابل کلیک HTML و سپس اتصال آنها به کامپوننتهای برنامه. استفادهی کاربر از bookmark مرورگر و یا ورود مستقیم و دستی آدرس قسمتی از برنامه و یا کلیک بر روی دکمههای forward و back مرورگر. تنها مورد اول است که نیاز به تنظیم دارد و سایر قسمتها به صورت خودکار مدیریت خواهند شد. نمونهی آنرا نیز با تعریف لینک Home پیشتر مشاهده کردید:
<a [routerLink]="['/home']">Home</a>
- زمانیکه کاربر بر روی این لینک کلیک میکند، اولین path متناظر با routerLink یافت شده و فعالسازی خواهد شد.
- علت تعریف مقدار routerLink به صورت [] این است که آرایهی پارامترهای لینک را مشخص میکند. بنابراین چون آرایهاست، نیاز به [] دارد. اولین پارامتر این آرایه مفهوم root URL segment را دارد. در اینجا حتما نیاز است URL segment را با یک / شروع کرد. به علاوه باید دقت داشت که خاصیت path تنظیمات مسیریابی، حساس به حروف کوچک و بزرگ است. بنابراین این مورد را باید در اینجا نیز مدنظر داشت.
- پارامترهای دیگر routerLink میتوانند مفهوم پارامترهای این segment و یا حتی segments دیگری باشند.
یک نکته: چون در مثال فوق، آرایهی تعریف شده تنها دارای یک عضو است، آنرا میتوان به صورت ذیل نیز خلاصه نویسی کرد (one-time binding):
<a routerLink="/home">Home</a>
تفاوت بین آدرسهای HTML 5 و Hash-based
زمانیکه مسیریاب Angular کار پردازش آدرسهای رسیده را انجام میدهد، اینکار در سمت کلاینت صورت میگیرد و تنها URL segment مدنظر را تغییر داده و این درخواست را به سمت سرور ارسال نمیکند. به همین جهت سبب reload صفحه نمیشود. دو روش در اینجا جهت مدیریت سمت کلاینت آدرسها قابل استفاده است:
الف) HTML 5 Style
- آدرسی مانند http://localhost:4200/home، یک آدرس به شیوهی HTML 5 است. در اینجا مسیریاب Angular با استفاده از HTML 5 history pushState سبب به روز رسانی History مرورگر شده و آدرسها را بدون ارسال درخواستی به سمت سرور، در همان سمت کلاینت تغییر میدهد.
- این روش حالت پیش فرض Angular است و نحوهی نمایش آن بسیار طبیعی به نظر میرسد.
- در اینجا URL rewriting سمت سرور نیز جهت هدایت آدرسها، به برنامهی Angular ضروری است. برای مثال زمانیکه کاربری آدرس http://localhost:4200/home را مستقیما در مرورگر وارد میکند، این درخواست ابتدا به سمت سرور ارسال خواهد شد و چون چنین صفحهای در سمت سرور وجود ندارد، پیغام خطای 404 را دریافت میکند. اینجا است که URL rewriting سمت سرور به فایل index.html برنامه، جهت مدیریت یک چنین حالتهایی ضروری است.
برای نمونه اگر از وب سرور IIS استفاده میکنید، تنظیم ذیل را به فایل web.config در قسمت system.webServer اضافه کنید (کار کرد آن هم وابستهاست به نصب و فعالسازی ماژول URL Rewrite بر روی IIS):
<rewrite> <rules> <rule name="Angular 2+ pushState routing" stopProcessing="true"> <match url=".*" /> <conditions logicalGrouping="MatchAll"> <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" /> <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" /> <add input="{REQUEST_FILENAME}" pattern=".*\.[\d\w]+$" negate="true" /> <add input="{REQUEST_URI}" pattern="^/(api)" negate="true" /> </conditions> <action type="Rewrite" url="/index.html" /> </rule> </rules> </rewrite>
ب) Hash-based
- آدرسی مانند http://localhost:4200/#/home یک آدرس به شیوهی Hash-based بوده و مخصوص مرورگرهایی است بسیار قدیمی که از HTML 5 پشتیبانی نمیکنند. اینبار قطعات قرار گرفتهی پس از علامت # دارای نام URL fragments بوده و قابلیت پردازش در سمت کلاینت را دارا میباشند.
- اگر علاقمند به استفادهی از این روش هستید، نیاز است خاصیت useHash را به true تنظیم کنید:
@NgModule({ imports: [RouterModule.forRoot(routes, { useHash: true })],
در تصویر بالا دو مسیر با آدرسهای : ShowPage1/ و ShowPage2/ تعریف شده است که هر کدام به یک view مشخص و یک Controller برای مدیریت آن اشاره میکند.
زمانی که ما از تزریق وابستگیها در AngularJs استفاده میکنیم و یک شیء را به کنترلر تزریق میکنیم، Angular توسط Injector$ سعی در پیدا کردن وابستگی مربوطه و سپس تزریق آن به کنترلر را انجام میدهد. برای استفاده از امکان مسیریابی Route ، ما نیز باید از پروایدر مخصوص آن برای تزریق استفاده کنیم. در Angular مسیرهای برنامه توسط پروایدری به نام routeProvider$ شناسایی میشود که خدمات مسیریابی را به ما ارائه میدهد. این سرویس به ما کمک میکند تا بتوانیم اتصال بین کنترلر ها، ویوها و آدرس URL جاری مرورگرها را به آسانی برقرار کنیم.
بهتر است کار را شروع کنیم . یک فایل JS ایجاد و سپس محتویات زیر را در آن قرار دهید :
var myFirstRoute = angular.module('myFirstRoute', []); myFirstRoute.config(['$routeProvider', function($routeProvider) { $routeProvider. when('/pageOne', { templateUrl: 'templates/page_one.html', controller: 'ShowPage1Controller' }). when('/pageTwo', { templateUrl: 'templates/page_two.html', controller: 'ShowPage2Controller' }). otherwise({ redirectTo: '/pageOne' }); }]); myFirstRoute.controller('ShowPage1Controller', function($scope) { $scope.message = 'Content of page-one.html'; }); myFirstRoute.controller('ShowPage2Controller', function($scope) { $scope.message = 'Content of page-two.html'; });
در کدهای بالا ابتدا یک ماژول تعریف کرده ایم و سپس توسط ()config. تنظیمات مربوط به مسیریابی را انجام داده ایم. با استفاده از متدهای when. و otherwise. میتوانیم مسیرها را تعریف کنیم. برای هر مسیر دو پارامتر وجود دارد که اولین پارامتر نام مسیر و دومین پارامتر شامل 2 قسمت میشود که templateUrl آن آدرسی که باز خواهد شد و controller نیز نام کنترلری که ویو را مدیریت میکند.
توسط otherwise میتوانیم مسیر پیشفرض را نیز تعریف کنیم تا درصورتی که مسیری با آدرسهای بالای آن مطابقت نداشت به این آدرس منتقل شود.
در قطعه کد بالا همچنین دو مسیر با نامهای pageOne/ و pageTwo/ تعریف کرده ایم که هر کدام به ترتیب به Viewهای : templates/page_one.html و templates/page_two.html مرتبط شده اند. همچنین دو کنترلر برای مدیریت ویوها نیز تعریف شده است.
زمانی که ما آدرس http://appname/#pageOne را در نوار آدرس مرورگر وارد میکنیم، Angular به صورت اتوماتیک آدرس URL را با تنظیماتی که ما در اینجا تعریف کرده ایم مطابقت میدهد و در صورت وجود چنین آدرسی ، view مربوطه را بارگزاری میکند و در این مثال نیز مطابق با تنظیمات بالا، صفحهی templates/page_one.html برای ما بارگزاری و سپس کنترلر ShowPage1Controller را فراخوانی میکند ، جایی که ما منطق کار را در آن قرار میدهیم.
محتویات فایل main.html :
<body ng-app="app"> <div> <div> <div> <ul> <li><a href="#pageOne"> Show page one </a></li> <li><a href="#pageTwo"> Show page two </a></li> </ul> </div> <div> <div ng-view></div> </div> </div> </div> <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script> <script src="app.js"></script> </body>
در قطعه کد بالا دو لینک تعریف شده است که ویژگی href از علامت هش و نام صفحه تشکیل شده است. یکی از چیزهایی که شایان ذکر است ، دایرکتیو ng-view است. مکانی برای بارگزاری صفحات در آن.
ما میتوانیم این تگ را به سه شکل زیر نیز استفاده کنیم :
<div ng-view></div> .. <ng-view></ng-view> .. <div class="ng-view"></div>
محتویات صفحه templates/page_one.html :
<h2>Page One</h2> {{ message }}
محتویات صفحه templates/page_two.html :
<h2>Page Two</h2> {{ message }}
حال اگر پروژه را اجرا کنید و به کنسول مرور گر خود نگاه کنید متوجه میشوید که مسیریاب از مسیر پیشفرض استفاده کرده است و صفحهی page_one.html را به صورت ایجکسی فراخوانی کرده است :
و اگر روی لینک Show Page two کلیک کنید ، صفحهی page_two.html نیز به صورت ایجکسی فراخوانی میشود.
دوباره بر روی لینک Show page one کلیک کنید. بله. هیچ درخواستی به سمت سرور ارسال نشد و صفحهی page_one.html به خوبی نمایش داده شد. یکی از مزیتهای سیستم مسیریابی قابلیت کش کردن صفحات است تا در صورت فراخوانی مجدد، درخواستی به سمت سرور ارسال نشود و خیلی سریع به شما نمایش داده شود.
مثال این مطلب : RouteExample.zip
ادامه دارد ...