اگه از کتاب خوشتون اومد به گیتهابمون مراجعه کنین و بهمون ⭐️ بدین. اگر هم قصد مشارکت داشتید همونجا میتونین شروع کنین و ما هم خیلی خوشحال میشیم 😃
لینک گیتهاب ما برای مشارکت برای تولید کتابها: https://github.com/mariotek
میتونین خیلی راحت نسخه آنلاین کتاب استفاده کنین یا اگه به فایل کتاب میخوایین دسترسی داشته باشین، از بخش ریلیزهای گیتهاب به فرمتهای مختلف آخرین نسخه کتاب رو میتونین دریافت کنین.
Angular یک پلتفرم فرانتاند اوپن سورس مبتنی بر TypeScript هس که ساخت برنامهها تو وب/موبایل/کامپیوتر رو برامون اسونتر میکنه. از ویژگی های اصلی این فریم ورک میشه به قالب های declarative dependency injection، ابزارهای end to end و خیلی ویژگی های دیگه که برای اسونتر شدن توسعه استفاده میشه اشاره کرد.
Angular یه فریم ورک کاملاً کامپوننت بیس هستش که تو اون یه app ساختار درختی از کامپوننت ها هستش.
AngularJS | Angular |
---|---|
بر اساس معماری MVC هستش | بر اساس Service/Controller هستش |
از جاوا اسکریپت برای ساخت app استفاده میکنه | برای نوشتن app، TypeScript رو معرفی کرد |
بر اساس مفهوم کنترلرها | یه رویکرد UI مبتنی بر کامپوونت هستش |
یک چارچوب سازگار با موبایل نیست | میشه برای پلتفرم تلفن همراه ازش استفاده کرد |
ساخت برنامه با مشکلات مربوط به سئو | ساخت برنامه با سئو مناسب |
TypeScript یک ابر مجموعه تایپ های جاوا اسکریپت هستش که توسط مایکروسافت ساخته شده که انواع تایپ های optional، class ها، async/wait و خیلی ویژگی های دیگه رو اضافه می کنه و به جاوا اسکریپت ساده کامپایل می کنه. Angular به طور کامل تو TypeScript ساخته شده و به عنوان زبان اصلی استفاده می شه.
ما می تونیم اونو به صورت گلوبال نصب کنیم
npm install -g typescript
بیاین یه مثال از نحوه استفاده از تایپ اسکریپت ببینیم
function greeter(person: string) { return "Hello, " + person; } let user = "Sudheer"; document.body.innerHTML = greeter(user);
متد greeter فقط تایپ string رو به عنوان آرگومان اجازه میده.
بلوک های ساختمان اصلی یک برنامه Angular رو میتونیم توی دیاگرام زیر ببینیم
Component: اینها بلوک های ساخت اصلی برنامه های انگولار برای کنترل نماهای HTML هستش.
Modules: یک ماژول انگولار مجموعهای از بلوکهای ساخت پایه انگولار مثل کامپوننت، directive ها service ها و غیره هستش. یک برنامه کاربردی به قطعات منطقی تقسیم میشه و هر قطعه کد به عنوان "ماژول" ازش استفاده میشه که یه وظیفه رو انجام میده.
Templates: این نماهای یک برنامه Angular رو نشون میده.
Services: برای ایجاد مؤلفه هایی استفاده می شه که می تونن تو کل برنامه به اشتراک گذاشته شن.
Metadata: از این مورد می تونیم برای اضافه کردن داده های بیشتر به یک کلاس Angular استفاده کنیم.
directive ها رفتاری رو به یه کامپوننت DOM موجود یا یه المنت موجود Dom اضافه می کنن.
import { Directive, ElementRef, Input } from '@angular/core'; @Directive({ selector: '[myHighlight]' }) export class HighlightDirective { constructor(el: ElementRef) { el.nativeElement.style.backgroundColor = 'yellow'; } }
این directive رفتار عنصر HTML رو با پسزمینه زرد رو اینطوری پیاده سازی میکنه
<p myHighlight>Highlight me!</p>
کامپوننت ها اساسی ترین بلوک سازنده رابط کاربری یک برنامه Angular هستن که درختی از اجزای Angular رو تشکیل هستن. این مؤلفه ها زیر مجموعه directive ها هست. برخلاف دستورات، کامپوننتها همیشه دارای یک الگون و تنها یک جزء رو میشه به ازای هر عنصر تو قالب نمونهسازی کرد.
یک مثال ساده از کامپوننت Angular رو ببینیم
import { Component } from '@angular/core'; @Component ({ selector: 'my-app', template: ` <div> <h1>{{title}}</h1> <div>Learn Angular6 with examples</div> </div> `, }) export class AppComponent { title: string = 'Welcome to Angular world'; }
Component | Directive |
---|---|
برای ثبت یه کامپوننت از meta-data @Component استفاده می کنیم | برای ثبت directive ها از meta-data @Directive استفاده میکنیم |
کامپوننت ها معمولا برای ایجاد ویجت های UI استفاده می شن | directive ها برای افزودن رفتار به یک عنصر DOM موجود استفاده می شن |
کامپوننت برای تقسیم برنامه به اجزای کوچکتر استفاده می شه | دستورالعمل برای طراحی اجزای قابل استفاده مجدد استفاده می شه |
فقط یک جزء می تونه تو هر عنصر DOM وجود داشته باشه | بسیاری از directive ها رو میشه برای هر عنصر DOM استفاده کرد |
@View decorator یا templateurl/template اجباریه | دستورالعمل از View استفاده نمیکنه |
یک template یک نمای HTML هس که توی اون می تونیم داده ها رو با اتصال کنترل ها به ویژگی های یک جزء Angular نشون بدیم. می تونیم الگوی جزء خودمون رو تو یکی از دو مکان ذخیره کنیم. می تونیم با استفاده از ویژگی template اون رو به صورت درون خطی تعریف کینم یا می تونیم قالب رو توی یک فایل HTML جداگانه تعریف کنیم و با استفاده از ویژگی templateUrl@Component decorator به اون تو ابرداده کامپوننت پیوند بدیم.
Using inline template with template syntax,
import { Component } from '@angular/core'; @Component ({ selector: 'my-app', template: ' <div> <h1>{{title}}</h1> <div>Learn Angular</div> </div> ' }) export class AppComponent { title: string = 'Hello World'; }
Using separate template file such as app.component.html
import { Component } from '@angular/core'; @Component ({ selector: 'my-app', templateUrl: 'app/app.component.html' }) export class AppComponent { title: string = 'Hello World'; }
ماژول ها مرزهای منطقی تو برنامه هستن و برنامه به ماژول های جداگانه تقسیم می شن که عملکرد برنامه رو از هم جدا کنن.
بیاین مثالی از app.module.ts ماژول core رو که با دکوراتور @NgModule بزنیم.
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; @NgModule ({ imports: [ BrowserModule ], declarations: [ AppComponent ], bootstrap: [ AppComponent ], providers: [] }) export class AppModule { }
دکوراتور NgModule پنج گزینه مهم ( میان همه) داره
گزینه imports برای وارد کردن ماژول های وابسته دیگر استفاده می شه. BrowserModule به طور پیش فرض برای هر برنامه انگولار مبتنی بر وب لازمه
گزینه declarations برای تعریف اجزا تو ماژول مربوطه استفاده می شه
گزینه bootstrap به Angular می گه که کدوم کامپوننت رو تو برنامه بوت استرپ کنه
گزینه providers برای پیکربندی مجموعه ای از اشیاء تزریقی موجود تو انژکتور این ماژول استفاده می شن.
گزینه enterComponents مجموعه ای از اجزاییه که به صورت پویا تو view بارگذاری می شن.
Angular مجموعه کاملی از فرآیندها رو طی می کنه یا از زمان شروع تا پایان برنامه یک lifecycle دارد.
نمایش lifecycle رو متونیم تو شکل زیر ببینیم:
ngOnChanges: هنگامی که مقدار یک ویژگی داده محدود تغییر می کنه این روش فراخوانی می شه.
ngOnInit: هر زمان که مقداردهی اولیه دستور/کامپوننت پس از نمایش Angular برای اولین بار خصوصیات داده محدود اتفاق بیفتد، فراخوانی می شه.
ngDoCheck: این برای تشخیص و اعمال تغییراتی است که Angular به تنهایی قادر به تشخیص آنها نیست یا نخواهد بود.
ngAfterContentInit: پس از اینکه Angular محتوای خارجی را در نمای کامپوننت پروژه میده، در پاسخ به این امر فراخوانی می شه.
ngAfterContentChecked: این در پاسخ پس از بررسی Angular محتوای پیش بینی شده در کامپوننت فراخوانی می شه.
ngAfterViewInit: پس از اینکه Angular نماهای کامپوننت و نماهای فرزند را مقدار دهی اولیه کرد، در پاسخ فراخوانی می شه.
ngAfterViewChecked: این در پاسخ پس از بررسی Angular نماهای کامپوننت و نماهای فرزند فراخوانی می شه.
ngOnDestroy: این مرحله پاکسازی درست قبل از اینکه Angular دستور/کامپوننت را از بین ببرد است.
Data binding یک مفهوم اصلی در Angular است و امکان تعریف ارتباط بین یک مؤلفه و DOM رو فراهم میکنه و تعریف برنامه های تعاملی رو بدون نگرانی در مورد فشار دادن و کشیدن داده ها بسیار آسان میکنه. چهار شکل اتصال داده وجود دارد (به 3 دسته تقسیم می شه) که در نحوه جریان داده ها متفاوت است.
From the Component to the DOM:
Interpolation: {{ value }}: مقدار یک ویژگی رو از جزء اضافه می کنه
<li>Name: {{ user.name }}</li> <li>Address: {{ user.address }}</li>
Property binding: [property]=”value”: مقدار از کامپوننت به ویژگی مشخص شده یا ویژگی ساده HTML منتقل می شه.
<input type="email" [value]="user.email">
<button (click)="logout()"></button>
<input type="email" [(ngModel)]="user.email">
metadata برای تزئین یک کلاس استفاده میشه تا بتونه رفتار مورد انتظار کلاس را پیکربندی کنه. metadata توسط دکوراتورها نمایش داده می شه
Class decorators, برای مثال، @Component و @NgModule
import { NgModule, Component } from '@angular/core'; @Component({ selector: 'my-component', template: '<div>Class decorator</div>', }) export class MyComponent { constructor() { console.log('Hey I am a component!'); } } @NgModule({ imports: [], declarations: [], }) export class MyModule { constructor() { console.log('Hey I am a module!'); } }
Property decorators برای ویژگی های داخل کلاس ها استفاده می شه برای مثال. @import و export
import { Component, Input } from '@angular/core'; @Component({ selector: 'my-component', template: '<div>Property decorator</div>' }) export class MyComponent { @Input() title: string; }
Method decorators برای متدهای داخل کلاس ها استفاده می شه برای مثال. @HostListener
import { Component, HostListener } from '@angular/core'; @Component({ selector: 'my-component', template: '<div>Method decorator</div>' }) export class MyComponent { @HostListener('click', ['$event']) onHostClick(event: Event) { // clicked, `event` available } }
Parameter decorators برای پارامترهای داخل سازنده کلاس استفاده می شه برای مثال. @Inject، اختیاری
import { Component, Inject } from '@angular/core'; import { MyService } from './my-service'; @Component({ selector: 'my-component', template: '<div>Parameter decorator</div>' }) export class MyComponent { constructor(@Inject(MyService) myService) { console.log(myService); // MyService } }
Angular CLI (Command Line Interface) یک رابط خط فرمان برای ساخت چارچوب مشخص و ساخت برنامه های انگولار با استفاده از ماژول های استایل nodejs (commonJs) است.
شما باید با استفاده از دستور زیر npm نصب کنید،
npm install @angular/cli@latest
لیست زیر لیستی از چند دستور که هنگام ایجاد پروژه های انگولار ای به کار میان آورده شده
ساخت یه پروژه: ng new
ساخت Component ها, Directive ها و Service ها: ng generate/g
انواع مختلف دستورات
ng generate class my-new-class: یک کلاس به برنامه خودتون اضافه کنین
ng تولید کامپوننت my-new-component: یک کامپوننت به برنامه خودتون اضافه کنین
ng generate directive my-new-directive: یک directive به برنامه خودتون اضافه کنین
ng generate enum my-new-enum: یک enum به برنامه خودتون اضافه کنین
ng generate module my-new-module: یک ماژول به برنامه خودتون اضافه کنین
تولید لوله my-new-pipe: یک pipe به برنامه خودتون اضافه کنین
ng generate service my-new-service: یک service به برنامه خودتون اضافه کنین
برای اجرای پروژه: ng serve
کلاس های TypeScript دارای یک روش پیش فرض به نام constructor هستش که معمولاً برای هدف اولیه استفاده می شه. در حالی که روش ngOnInit مختص Angular است، به ویژه برای تعریف اتصالات Angular استفاده می شه. حتی اگه constructor ابتدا فراخوانی میشه، ترجیح داده میشه همه اتصالات Angular خود را به متد ngOnInit منتقل کنین.
برای استفاده از ngOnInit، باید رابط OnInit را به صورت زیر پیاده سازی میشه.
export class App implements OnInit{ constructor(){ //called first time before the ngOnInit() } ngOnInit(){ //called after the constructor and called after the first ngOnChanges() } }
یه service زمانی استفاده می شه که یک عملکرد مشترک باید به ماژول های مختلف انجام شه. سرویسها به شما اجازه میده تا نگرانیهای مربوط به برنامه شما را بیشتر از هم جدا و ساختار ماژولاریت بهتری داشته باشین، چون به شما امکان میده عملکردهای مشترک رو از اجزا خارج کنین.
بیاین یه repoService ایجاد کنیم که می تونه بین کامپوننت ها استفاده شه
import { Injectable } from '@angular/core'; import { Http } from '@angular/http'; @Injectable({ // The Injectable decorator is required for dependency injection to work // providedIn option registers the service with a specific NgModule providedIn: 'root', // This declares the service with the root app (AppModule) }) export class RepoService{ constructor(private http: Http){ } fetchAll(){ return this.http.get('https://api.github.com/repositories'); } }
سرویس بالا از سرویس Http به عنوان یک وابستگی استفاده می کنه.
dependency injection(DI)، یک الگوی طراحی برنامه مهمیه که تو اون یه کلاس به جای ایجاد dependency از منابع خارجی درخواست کنه. Angular با چارچوب dependency injection خود برای حل dependency ها (سرویس ها یا اشیایی که یک کلاس برای انجام عملکرد خود به آن نیاز داره) ارائه می شه. بنابراین می تونین service هاتون رو تو کل برنامه به سرویس های دیگر وابسته کنین.
AsyncPipe مشترک یک قابل مشاهده یا قول می شه و آخرین مقداری رو که منتشر کرده برمی گردونه. هنگامی که یه مقدار جدید منتشر می شه، pipe مؤلفه ای رو که باید بررسی شه برای تغییرات علامت گذاری می کنه.
بیاین یک زمان قابل مشاهده را در نظر بگیریم که به طور مداوم نما را برای هر 2 ثانیه با زمان فعلی به روز می کنه.
@Component({ selector: 'async-observable-pipe', template: `<div><code>observable|async</code>: Time: {{ time | async }}</div>` }) export class AsyncObservablePipeComponent { time = new Observable(observer => setInterval(() => observer.next(new Date().toString()), 2000) ); }
می تونین الگوی کامپوننت خودتون رو تو یکی از دو مکان ذخیره کنین. می تونین اون رو به صورت درون خطی با استفاده از ویژگی template تعریف کنین، یا می تونین الگو رو در یک فایل HTML جداگانه تعریف کنین و با استفاده از ویژگی templateUrl در decorator @Component به اون در ابرداده کامپوننت پیوند بدین.
انتخاب بین HTML درون خطی و مجزا یک موضوع سلیقه، شرایط و خط مشی سازمان است. اما معمولاً از قالب درون خطی برای بخش کوچکی از کد و از فایل قالب خارجی برای نمایش های بزرگتر استفاده می کنیم. به طور پیش فرض، Angular CLI کامپوننت ها رو با یک فایل الگو تولید می کنه. اما می تونین با دستور زیر اون رو لغو کنین
ng generate component hero -it
ما از directive Angular ngFor در قالب برای نمایش هر آیتم در لیست استفاده می کنیم. برای مثال، در اینجا ما روی لیست کاربران تکرار می کنیم،
<li *ngFor="let user of users"> {{ user }} </li>
متغیر کاربر در دستورالعمل ngFor دو نقل قول a استtemplate input variable
گاهی اوقات یه برنامه فقط در شرایط خاص نیاز به نمایش یه view یا بخشی از یه view داره. دستورالعمل Angular ngIf یک عنصر را بر اساس شرایط درستی/نادرستی درج یا حذف می کنه. اگر سن کاربر بیش از 18 سال باشد، برای نمایش پیام مثالی می زنیم.
<p *ngIf="user.age > 18">You are not eligible for student pass!</p>
Note: Angular پیام را نشان نمی دهد و پنهان نمی کنه. در حال افزودن و حذف عنصر پاراگراف از DOM است. که عملکرد را بهبود میده به خصوص در پروژه های بزرگتر با اتصال داده های زیادی.
Angular مقدار رو ناامن تشخیص میده و بهطور خودکار آن رو پاکسازی میکنه، که تگ «اسکریپت» رو حذف میکند اما محتوای ایمن مانند محتوای متنی برچسب «اسکریپت» رو حفظ میکنه. به این ترتیب خطر حملات تزریق اسکریپت رو از بین می برد. اگر همچنان از آن استفاده می کنید، نادیده گرفته می شه و یک هشدار در کنسول مرورگر ظاهر می شه.
بیایید مثالی از اتصال ویژگی innerHtml که باعث آسیبپذیری XSS میشه بیاوریم.
export class InnerHtmlBindingComponent { // For example, a user/attacker-controlled value from a URL. htmlSnippet = 'Template <script>alert("0wned")</script> <b>Syntax</b>'; }
interpolation یه نحو خاصیه که Angular آن رو به ویژگی binding تبدیل می کنه. این یه جایگزین مناسب برای اتصال اموال است. با مهاربندهای دوتایی ({{}}) نشان داده میشه. متن بین پرانتزها اغلب نام یه ویژگی جزء است. Angular آن نام را با مقدار رشته خاصیت جزء مربوطه جایگزین می کنه.
بیاین یه مثال بزنیم،
<h3> {{title}} <img src="{{url}}" style="height:30px"> </h3>
در مثال بالا، Angular خصوصیات عنوان و url رو ارزیابی می کنه و جاهای خالی رو پر می کنه، ابتدا عنوان برنامه پررنگ و سپس URL نمایش داده می شه.
یه template expression مقداری شبیه به هر عبارت جاوا اسکریپت تولید می کنه. Angular عبارت رو اجرا می کنه و اون رو به به دیتای هدف اضافه میکنه. هدف ممکنه یه عنصر HTML، یه کامپوننت یا یه directive باشد. در ویژگی binding، یه template expression تو نقل قول تو سمت راست نماد = مثل [property]="expression ظاهر می شه.
در نحو درون یابی، template expression با پرانتزهای مجعد دوتایی احاطه شده. برای مثال، در درون یابی پایین template expression {{username}} هستش
<h3>{{username}}, welcome to Angular</h3>
عبارات جاوا اسکریپت زیر در عبارت قالب ممنوع هستن
assignments (=، +=، -=، ...)
new
زنجیره عبارات با ; یا ،
عملگرهای افزایش و کاهش (++ و --)
یه template statements به رویدادی پاسخ میده که توسط یک دیتای هدف مثل یک المنت مؤلفه یا directive ساخته شده. عبارات الگو تو نقل قول تو سمت راست نماد = مانند (رویداد)="statement" ظاهر می شن.
بیاین برای گذاشتن ایونت روی دکمه یه مثال بزنیم
<button (click)="editProfile()">Edit Profile</button>
تو عبارت بالا، editProfile یه template expration هستش. عبارات نحوی جاوا اسکریپت زیر مجاز نیستند.
new
عملگرهای افزایش و کاهش، ++ و --
انتساب عملگر، مانند += و -=
عملگرهای بیتی | و &
عملگرهای template expression
انواع اتصال رو میشه به سه دسته دسته بندی کرد که با جهت جریان داده ها متمایز می شن:
source-to-view
view-to-source
View-to-source-to-view
دیتا هدف خروجی رو می توان به صورت جدولی در زیر ارائه کرد:
جهت داده | نحو | نوع |
---|---|---|
از منبع به مشاهده (یک طرفه) | 1. {{expression}} 2. [target]="expression" 3. bind-target="expression" | درون یابی، ویژگی، صفت، طبقه، سبک |
از دیدگاه به منبع (یک طرفه) | 1. (target)="statement" 2. on-target="statement" | رویداد |
View-to-source-to-view(دو طرفه) | 1. [(target)]="expression" 2. bindon-target="expression" | دوطرفه |
یک pipe داده ها رو به عنوان ورودی می گیره و اون رو به خروجی دلخواه تبدیل می کنه. برای مثال، اجازه بدین یک pipe رو برای تبدیل ویژگی birthday کامپوننت به تاریخ قابل استفاده با استفاده از pipe date در نظر بگیریم.
import { Component } from '@angular/core'; @Component({ selector: 'app-birthday', template: `<p>Birthday is {{ birthday | date }}</p>` }) export class BirthdayComponent { birthday = new Date(1987, 6, 18); // June 18, 1987 }
یه pipe می تونه هر تعداد پارامتر اختیاری رو برای تنظیم دقیق خروجیش قبول کنه. pipe پارامتر شده رو می شه با اعلام نام pipe با علامت دو نقطه ( : ) و بعد مقدار پارامتر ایجاد کرد. اگه pipe چن تا پارامتر رو میگیرع مقادیر رو با دو نقطه جدا کنین. بیاین یک مثال تولد با یک قالب خاص (dd/MM/yyyy) در نظر بگیریم:
import { Component } from '@angular/core'; @Component({ selector: 'app-birthday', template: `<p>Birthday is {{ birthday | date:'dd/MM/yyyy'}}</p>` // 18/06/1987 }) export class BirthdayComponent { birthday = new Date(1987, 6, 18); }
Note: مقدار پارامتر می تونه هر عبارت الگوی معتبری باشه مثل یه رشته لفظی یا یه ویژگی جزء.
میتونین pipe رو تو ترکیبهای بالقوه مفید بر حسب نیاز به هم زنجیر کنین. بیایید یه ویژگی تولد رو تو نظر بگیریم که از لوله تاریخ (همراه با پارامتر) و pipe های بزرگ مثل زیر استفاده می کنه
import { Component } from '@angular/core'; @Component({ selector: 'app-birthday', template: `<p>Birthday is {{ birthday | date:'fullDate' | uppercase}} </p>` // THURSDAY, JUNE 18, 1987 }) export class BirthdayComponent { birthday = new Date(1987, 6, 18); }
جدا از pipe های داخلی، می تونین pipe سفارشی خود رو با ویژگی های کلیدی زیر بنویسید:
@Pipe({name: 'myCustomPipe'})
interface PipeTransform {
transform(value: any, ...args: any[]): any
}
دکوراتور @Pipe به شما امکان می ده نام pipe تو عبارات قالب استفاده می کنید، تعریف کنید. باید یه شناسه جاوا اسکریپت معتبر باشه.
template: `{{someInputValue | myCustomPipe: someOtherValue}}`
ما می تونیم pipe های قابل استفاده مجدد سفارشی برای تغییر ارزش موجود ایجاد کنیم. برای مثال، اجازه بدین یه pipe سفارشی برای یافتن اندازه فایل بر اساس پسوند ایجاد کنیم،
import { Pipe, PipeTransform } from '@angular/core'; @Pipe({name: 'customFileSizePipe'}) export class FileSizePipe implements PipeTransform { transform(size: number, extension: string = 'MB'): string { return (size / (1024 * 1024)).toFixed(2) + extension; } }
حالا می تونیم از pipe بالا تو قالب عبارت پایین استفاده کنیم.
template: `
<h2>Find the size of a file</h2>
<p>Size: {{288966 | customFileSizePipe: 'GB'}}</p>
`
یه pipe خالص تنها زمانی فراخوانی میشه که Angular تغییر تو مقدار یا پارامترهای ارسال شده به یه pipe رو تشخیص بده. برای مثال، هرگونه تغییر تو یه مقدار ورودی اولیه (رشته، عدد، بولی، نماد) یا یه مرجع شی تغییر یافته (تاریخ، آرایه، تابع، object). یه pipe ناخالص برای هر چرخه تشخیص تغییر بدون توجه به تغییر مقدار یا پارامترها فراخوانی میشه. برای مثال، یه pipe ناخالص اغلب، به اندازه هر ضربه کلید یا حرکت ماوس، نامیده میشه.
هر برنامه حداقل یک ماژول Angular دارد، ماژول ریشه ای که برای راه اندازی برنامه بوت استرپ می کنید ماژول بوت استرپینگ نامیده میشه. معمولاً به عنوان AppModule شناخته میشه. ساختار پیش فرض AppModule تولید شده توسط AngularCLI رو اینطوری انجام میدیم:
/* JavaScript imports */ import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { HttpClientModule } from '@angular/common/http'; import { AppComponent } from './app.component'; /* the AppModule class with the @NgModule decorator */ @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, FormsModule, HttpClientModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
مشاهده پذیرها بیانی هستند که از ارسال پیام بین ناشران و مشترکین تو برنامه شما پشتیبانی می کنن. آنها عمدتاً برای مدیریت رویداد، برنامه نویسی ناهمزمان و مدیریت چندین مقدار استفاده میشن. تو اون مورد، شما تابعی رو برای انتشار مقادیر تعریف می کنین اما تا زمانی که یک مصرف کننده تو اون مشترک نشه اجرا نمیشه. بعد مصرف کننده مشترک تا زمانی که عملکرد کامل شه یا تا زمانی که اشتراکشون رو لغو نکنن اعلان ها رو دریافت کنن.
اکثر برنامه های کاربردی Front-end با استفاده از رابط XMLHttpRequest یا fetch() API از طریق پروتکل HTTP با سرویس های پشتیبان ارتباط برقرار می کنن. Angular یک API HTTP کلاینت ساده شده به نام HttpClient رو ارائه می دن که بر پایه رابط XMLHttpRequest است. این سرویس گیرنده از بسته «@angular/common/http» در دسترس است.
می تونین در ماژول ریشه خود به صورت زیر import کنین
import { HttpClientModule } from '@angular/common/http';
مزایای اصلی HttpClient رو می شه به شرح زیر ذکر کرد:
دارای ویژگی های تست پذیریه
اشیاء درخواست و پاسخ تایپ شده رو ارائه می ده
رهگیری درخواست و پاسخ
از API های Observalbe پشتیبانی میکنه
از مدیریت خطای ساده پشتیبانی میکنه
در زیر مراحلی که برای استفاده از HttpClient باید طی شود آورده شده است.
HttpClient را به ماژول root وارد کنید:
import { HttpClientModule } from '@angular/common/http'; @NgModule({ imports: [ BrowserModule, // import HttpClientModule after BrowserModule. HttpClientModule, ], // ...... }) export class AppModule {}
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; const userProfileUrl: string = 'assets/data/profile.json'; @Injectable() export class UserProfileService { constructor(private http: HttpClient) { } getUserProfile() { return this.http.get(this.userProfileUrl); } }
fetchUserProfile() { this.userProfileService.getUserProfile() .subscribe((data: User) => this.user = { id: data['userId'], name: data['firstName'], city: data['city'] }); }
از اونجایی که روش سرویس بالا یه Observable را برمی گردونه که باید تو کامپوننت ثبت شه.
ممکنه بدنه پاسخ دادههای پاسخ کامل را برنگردونه چون گاهی اوقات سرورها سرصفحهها یا کد وضعیت خاصی را که برای گردش کار برنامه مهم هستند، برمیگردونه. برای دریافت پاسخ کامل، باید از گزینه Observer از HttpClient استفاده کنیم.
getUserResponse(): Observable<HttpResponse<User>> { return this.http.get<User>( this.userUrl, { observe: 'response' }); }
اکنون متد HttpClient.get () یک Observable از HttpResponse تایپ شده را به جای داده های JSON برمی گرداند.
اگر درخواست در سرور ناموفق باشد یا به دلیل مشکلات شبکه به سرور نرسد، HttpClient به جای پاسخ موفقیت آمیز، یک شی خطا را برمی گرداند. در این مورد، باید با ارسال شیء خطا به عنوان متد ()subscribe، کامپوننت را کنترل کنید.
بیایید ببینیم که چگونه می توان آن را در کامپوننت با یک مثال مدیریت کرد،
fetchUser() { this.userService.getProfile() .subscribe( (data: User) => this.userProfile = { ...data }, // success path error => this.error = error // error path ); }
همیشه خوبه که به کاربر فیدبک معنی داری رو به جای ارورهای http برگردونیم
RxJS کتابخونه ای برای نوشتن کدهای async و مبتنی بر تماس به سبک عملکردی و واکنشی با استفاده از Observables است. بسیاری از APIها مانند HttpClient RxJS Observables را تولید و مصرف می کنند و همچنین از عملگرها برای پردازش مشاهده پذیرها استفاده می کنند.
برای مثال، می تونین مشاهده پذیرها و عملگرها را برای استفاده از HttpClient به صورت زیر وارد کنید.
import { Observable, throwError } from 'rxjs';
import { catchError, retry } from 'rxjs/operators';
یه instance Observable تنها زمانی شروع به انتشار مقادیر میکنه که شخصی در آن مشترک شود. بنابراین باید با فراخوانی متد subscribe() از نمونه، مشترک شوید و یه شی ناظر را برای دریافت اعلانها ارسال کنید.
بریم نمونهای از ساخت و subscribe در یه observable ساده، با observer ای که پیامی رو تو کنسول برمیگردونه در نظر بگیریم.
Creates an observable sequence of 5 integers, starting from 1 const source = range(1, 5); // Create observer object const myObserver = { next: x => console.log('Observer got a next value: ' + x), error: err => console.error('Observer got an error: ' + err), complete: () => console.log('Observer got a complete notification'), }; // Execute with the observer object and Prints out each item source.subscribe(myObserver); // => Observer got a next value: 1 // => Observer got a next value: 2 // => Observer got a next value: 3 // => Observer got a next value: 4 // => Observer got a next value: 5 // => Observer got a complete notification
Observable یک شی منحصر به فرد شبیه به Promise است که می تونه به مدیریت کدهای همگام کمک کنه. Observable ها بخشی از زبان جاوا اسکریپت نیستن بنابراین باید به یک کتابخونه معروف Observable به نام RxJS تکیه کنیم.
Observable ها با استفاده از کلمه کلیدی جدید ایجاد میشن.
مثال ساده Observable برای رو ببینیم
import { Observable } from 'rxjs';
const observable = new Observable(observer => {
setTimeout(() => {
observer.next('Hello from a Observable!');
}, 2000);
});
Observer یک رابط برای مصرف کننده اعلان های push-based است که توسط Observable ارائه میشه. ساختاری مثل مثال زیر داره
interface Observer<T> {
closed?: boolean;
next: (value: T) => void;
error: (err: any) => void;
complete: () => void;
}
کنترلکنندهای که رابط Observer را برای دریافت اعلانهای قابل مشاهده پیادهسازی میکنه بهعنوان پارامتری برای مشاهده پذیر ارسال شه.
myObservable.subscribe(myObserver);
Note: اگر یک کنترل کننده برای یک نوع اعلان ارائه نکنین ناظر اعلان های اون نوع رو نادیده می گیره.
oberservable | pronise |
---|---|
اعلامی: محاسبات تا زمان اشتراک شروع نمیشه تا هر زمان که به نتیجه نیاز داشتید، قابل اجرا باشند | اجرا بلافاصله پس از ایجاد |
ارائه مقادیر متعدد در طول زمان | فقط یک |
روش Subscribe برای مدیریت خطا استفاده میشه که مدیریت خطا را متمرکز و قابل پیش بینی میکنه | خطاها رو به فرزند promise ارسال میکنه |
ارائه زنجیره و اشتراک برای رسیدگی به برنامه های پیچیده | فقط از .then() بند |
multicasting عمل پخش به فهرستی از چند مشترک در یک اجرا هستش.
بیایید ویژگی چند ریختگی را نشان دهیم،
var source = Rx.Observable.from([1, 2, 3]); var subject = new Rx.Subject(); var multicasted = source.multicast(subject); // These are, under the hood, `subject.subscribe({...})`: multicasted.subscribe({ next: (v) => console.log('observerA: ' + v) }); multicasted.subscribe({ next: (v) => console.log('observerB: ' + v) }); // This is, under the hood, `s
شما میتوانید با تعیین یک بازخوانی خطا روی ناظر به جای تکیه بر try/catch که در محیط async بیاثر هستن خطاها را مدیریت کنین.
برای مثال، می تونین خطا رو اینطوری تعریف کنید.
myObservable.subscribe({
next(num) { console.log('Next num: ' + num)},
error(err) { console.log('Received an errror: ' + err)}
});
متد subscribe () میتونه تعاریف تابع برگشتی را بهصورت خطی قبول کنه برای کنترلکنندههای بعدی، خطا و کامل به عنوان نماد دست کوتاه یا متد Subscribe با آرگومانهای موقعیتی شناخته میشه.
برای مثال، می تونین متد subscribe رو به این صورت تعریف کنین.
myObservable.subscribe( x => console.log('Observer got a next value: ' + x), err => console.error('Observer got an error: ' + err), () => console.log('Observer got a complete notification') );
کتابخونه RxJS همچنین توابع کاربردی زیر را برای ایجاد و کار با مشاهده پذیرها ارائه می دهد.
تبدیل کدهای موجود برای عملیات همگام به قابل مشاهده
تکرار از طریق مقادیر در یک جریان
نگاشت مقادیر به انواع مختلف
فیلتر کردن جریان ها
آهنگسازی چند جریان
RxJS توابع ایجاد را برای فرآیند ایجاد observable از چیزهایی مانند promise ها، رویدادها، تایمرها و درخواست های Ajax فراهم میکنه. بیاین هر کدومشون رو با یک مثال توضیح بدیم
از promise یک observable ایجاد کنید
import { from } from 'rxjs'; // from function const data = from(fetch('/api/endpoint')); //Created from Promise data.subscribe({ next(response) { console.log(response); }, error(err) { console.error('Error: ' + err); }, complete() { console.log('Completed'); } });
Create an observable that creates an AJAX request
import { ajax } from 'rxjs/ajax'; // ajax function const apiData = ajax('/api/data'); // Created from AJAX request // Subscribe to create the request apiData.subscribe(res => console.log(res.status, res.response));
یک قابل مشاهده از یک شمارنده ایجاد کنید
import { interval } from 'rxjs'; // interval function const secondsCounter = interval(1000); // Created from Counter value secondsCounter.subscribe(n => console.log(`Counter value: ${n}` ));
یک قابل مشاهده از یک رویداد ایجاد کنید
import { fromEvent } from 'rxjs'; const el = document.getElementById('custom-element'); const mouseMoves = fromEvent(el, 'mousemove'); const subscription = mouseMoves.subscribe((e: MouseEvent) => { console.log(`Coordnitaes of mouse pointer: ${e.clientX} * ${e.clientY}`); });
به طور معمول یک شی ناظر می تونه هر ترکیبی از کنترل کننده های نوع اعلان بعدی، خطا و کامل را تعریف کنه. اگر یک کنترل کننده برای یک نوع اعلان تعریف نکنین ناظر فقط اعلان های آن نوع را نادیده می گیره.
عناصر انگولار، اجزای انگولار هستند که بهعنوان عناصر سفارشی (یک استاندارد وب برای تعریف عناصر جدید HTML به روشی فریمورک-آگنوستیک) بستهبندی شدهاند. Angular Elements میزبان یک کامپوننت Angular است که پلی بین داده ها و منطق تعریف شده در کامپوننت و APIهای استاندارد DOM ایجاد میکنه، بنابراین راهی برای استفاده از مولفه های Angular در "محیط های غیر انگولاری" ارائه می دهد.
از آنجایی که عناصر Angular به عنوان عناصر سفارشی بسته بندی میشن، پشتیبانی مرورگر از عناصر انگولاری مانند پشتیبانی از عناصر سفارشی است.
این ویژگی در حال حاضر به صورت بومی در تعدادی از مرورگرها پشتیبانی میشه و برای مرورگرهای دیگر در انتظار است.
مرورگر | پشتیبانی از المان انگولاری |
---|---|
کروم | پشتیبانی بومی |
اپرا | پشتیبانی بومی |
سافاری | پشتیبانی بومی |
فایرفاکس | به طور بومی از نسخه 63 به بعد پشتیبانی میشه. باید dom.webcomponents.enabled و dom.webcomponents.customelements.enabled را در مرورگرهای قدیمی فعال کنید |
Edge | در حال حاضر در حال انجام است |
عناصر سفارشی (یا اجزای وب) یک ویژگی پلتفرم وب هستند که HTML را با اجازه دادن به شما برای تعریف برچسبی که محتوای آن توسط کد جاوا اسکریپت ایجاد و کنترل میشه، گسترش می دهد. مرورگر یک «CustomElementRegistry» از عناصر سفارشی تعریف شده را حفظ میکنه، که یک کلاس جاوا اسکریپت غیر قابل مشاهده را به یک تگ HTML نگاشت میکنه. در حال حاضر این ویژگی توسط کروم، فایرفاکس، اپرا و سافاری پشتیبانی میشه و در مرورگرهای دیگر از طریق polyfills در دسترس است.
خیر، عناصر سفارشی هنگامی که به DOM اضافه میشن به طور خودکار راه اندازی میشن (یا شروع میشن) و وقتی از DOM حذف میشن به طور خودکار از بین می روند. هنگامی که یک عنصر سفارشی برای هر صفحه ای به DOM اضافه میشه، مانند هر عنصر HTML دیگری به نظر می رسد و رفتار میکنه و به دانش خاصی از Angular نیاز ندارد.
در زیر مراحل به ترتیب در مورد عملکرد عناصر سفارشی آمده است،
App registers custom element with browser: از تابع «createCustomElement()» برای تبدیل یک مؤلفه به کلاسی استفاده کنید که میتونه در مرورگر به عنوان یک عنصر سفارشی ثبت شود.
App adds custom element to DOM: عنصر سفارشی را درست مانند یک عنصر HTML داخلی مستقیماً به DOM اضافه کنید.
Browser instantiate component based class: مرورگر یک نمونه از کلاس ثبت شده ایجاد میکنه و آن را به DOM اضافه میکنه.
تبدیل اجزا به عناصر سفارشی شامل دو مرحله اصلی است،
کلاس عنصر سفارشی بسازید: Angular تابع "createCustomElement()" را برای تبدیل یک جزء Angular (همراه با وابستگی های آن) به یک عنصر سفارشی ارائه می ده. فرآیند تبدیل رابط «NgElementConstructor» را پیادهسازی میکند و یک کلاس سازنده ایجاد میکند که برای تولید یک نمونه self-bootstrapping از مؤلفه Angular استفاده میشه.
ثبت کلاس عنصر با مرورگر: از تابع JS «customElements.define()» برای ثبت سازنده پیکربندی شده و تگ عنصر سفارشی مرتبط با آن با «CustomElementRegistry» مرورگر استفاده میکنه. هنگامی که مرورگر با برچسب عنصر ثبت شده روبرو میشه، از سازنده برای ایجاد یک نمونه عنصر سفارشی استفاده میکنه.
The detailed structure would be as follows,
ویژگی های Component و منطق مستقیماً به ویژگی های HTML و سیستم رویداد مرورگر نگاشت میشن. اجازه دهید آنها را در دو مرحله توصیف کنیم،
CreateCustomElement() API خصوصیات ورودی کامپوننت را با ویژگی های مربوط به عنصر سفارشی تجزیه میکنه. برای مثال، جزء @Input('myInputProp') به عنوان ویژگی عنصر سفارشی 'my-input-prop' تبدیل شد.
خروجی های کامپوننت به صورت رویدادهای سفارشی HTML ارسال میشن که نام رویداد سفارشی با نام خروجی مطابقت دارد. برای مثال، کامپوننت @Output() valueChanged = New EventEmitter() به عنوان عنصر سفارشی با رویداد اعزام به عنوان "valueChanged" تبدیل شده است.
میتوانید از انواع «NgElement» و «WithProperties» که از @angular/elements صادر شدهاند استفاده کنید.
بیایید ببینیم که چگونه می توان آن را با مقایسه با کامپوننت Angular اعمال کرد.
ظرف ساده با ویژگی ورودی به صورت زیر خواهد بود.
@Component(...)
class MyContainer {
@Input() message: string;
}
پس از اعمال typescript مقدار ورودی و انواع آنها را تأیید میکنه.
const container = document.createElement('my-container') as NgElement & WithProperties<{message: string}>;
container.message = 'Welcome to Angular elements!';
container.message = true; // <-- ERROR: TypeScript knows this should be a string.
container.greet = 'News'; // <-- ERROR: TypeScript knows there is no `greet` property on `container`.
مؤلفههای پویا مؤلفههایی هستند که مکان مؤلفهها در برنامه در زمان ساخت تعریف نشده است، یعنی در هیچ قالب انگولار استفاده نمیشوند. اما کامپوننت نمونه سازی میشه و در زمان اجرا در برنامه قرار می گیرد.
مؤلفه ها - این دستورالعمل ها دارای یک الگو هستند.
دستورالعمل های ساختاری — این دستورالعمل ها با افزودن و حذف عناصر DOM، طرح DOM را تغییر می دهند.
دستورالعمل های ویژگی - این دستورالعمل ها ظاهر یا رفتار یک عنصر، جزء یا دستورالعمل دیگر را تغییر می دهند.
میتوانید از دستور CLI «ng generate directive» برای ایجاد فایل کلاس دستورالعمل استفاده کنید. فایل منبع (src/app/components/directivename.directive.ts
)، فایل آزمایشی مربوطه (.spec.ts) را ایجاد میکنه و فایل کلاس دستورالعمل را در ماژول ریشه اعلام میکنه.
بیایید رفتار ساده برجسته کننده را به عنوان یک دستورالعمل مثال برای عنصر DOM در نظر بگیریم. می تونین دستورالعمل ویژگی را با استفاده از مراحل زیر ایجاد و اعمال کنید:
کلاس HighlightDirective با نام فایل «src/app/highlight.directive.ts» ایجاد کنید. در این فایل، باید Directive را از کتابخونه هسته وارد کنیم تا متادیتا را اعمال کنیم و ElementRef را در سازنده دستورالعمل برای تزریق یک مرجع به عنصر DOM میزبان وارد کنیم.
import { Directive, ElementRef } from '@angular/core'; @Directive({ selector: '[appHighlight]' }) export class HighlightDirective { constructor(el: ElementRef) { el.nativeElement.style.backgroundColor = 'red'; } }
دستورالعمل ویژگی را به عنوان یک ویژگی در عنصر میزبان اعمال کنید (برای مثال،
)
<p appHighlight>Highlight me!</p>
برای مشاهده رفتار برجسته در عنصر پاراگراف، برنامه را اجرا کنید
ng serve
Angular Router مکانیزمی است که در آن هنگام انجام وظایف برنامه توسط کاربران، ناوبری از یک نمای به نمای بعدی انجام میشه. مفاهیم یا مدل ناوبری برنامه مرورگر را به عاریت گرفته است.
برنامه مسیریابی باید عنصر
<base href="/">
Angular Router که نمایانگر یک کامپوننت خاص برای یک URL معین است، بخشی از Angular Core نیست. در کتابخونه ای به نام «@angular/router» برای وارد کردن اجزای مورد نیاز روتر موجود است. برای مثال، ما آنها را در ماژول برنامه مانند زیر وارد می کنیم.
import { RouterModule, Routes } from '@angular/router';
RouterOutlet یک دستورالعمل از کتابخونه روتر است و به عنوان یک مکان نگهدار عمل میکنه که نقطه ای را در قالب مشخص میکنه که روتر باید اجزای آن خروجی را نمایش دهد. خروجی روتر مانند یک جزء استفاده میشه،
<router-outlet></router-outlet> <!-- Routed components go here -->
RouterLink یک دستورالعمل در تگ های لنگر است که به روتر کنترل آن عناصر را می دهد. از آنجایی که مسیرهای ناوبری ثابت هستند، می تونین مقادیر رشته ای را به دستورالعمل پیوند مسیریاب به صورت زیر اختصاص دهید.
<h1>Angular Router</h1> <nav> <a routerLink="/todosList" >List of todos</a> <a routerLink="/completed" >Completed todos</a> </nav> <router-outlet></router-outlet>
RouterLinkActive دستورالعملی است که کلاسهای css را برای اتصالات فعال RouterLink بر اساس RouterState فعلی تغییر میدهد. برای مثال، روتر کلاس های CSS را زمانی که این پیوند فعال است اضافه میکنه و زمانی که پیوند غیر فعال است حذف میکنه. برای مثال، می تونین آنها را مانند زیر به RouterLinks اضافه کنید.
<h1>Angular Router</h1> <nav> <a routerLink="/todosList" routerLinkActive="active">List of todos</a> <a routerLink="/completed" routerLinkActive="active">Completed todos</a> </nav> <router-outlet></router-outlet>
RouterState درختی از مسیرهای فعال شده است. هر گره در این درخت از بخش های URL "مصرف شده"، پارامترهای استخراج شده و داده های حل شده می داند. با استفاده از «سرویس روتر» و ویژگی «routerState» میتوانید از هر کجای برنامه به RouterState فعلی دسترسی داشته باشید.
@Component({templateUrl:'template.html'})
class MyComponent {
constructor(router: Router) {
const state: RouterState = router.routerState;
const root: ActivatedRoute = state.root;
const child = root.firstChild;
const id: Observable<string> = child.params.map(p => p.id);
//...
}
}
در طول هر ناوبری، روتر رویدادهای ناوبری را از طریق ویژگی Router.events منتشر میکنه که به شما امکان می دهد چرخه حیات مسیر را ردیابی کنید.
توالی رویدادهای روتر به شرح زیر است:
NavigationStart,
RouteConfigLoadStart,
RouteConfigLoadEnd,
RoutesRecognized,
GuardsCheckStart,
ChildActivationStart,
ActivationStart,
GuardsCheckEnd,
ResolveStart,
ResolveEnd,
ActivationEnd
ChildActivationEnd
NavigationEnd,
NavigationCancel,
NavigationError
Scroll
ActivatedRoute حاوی اطلاعاتی در مورد یک مسیر مرتبط با یک جزء بارگذاری شده در یک خروجی است. همچنین می توان از آن برای عبور از درخت حالت روتر استفاده کرد. ActivatedRoute به عنوان یک سرویس روتر برای دسترسی به اطلاعات تزریق میشه. در مثال زیر می تونین به مسیر و پارامترهای مسیر دسترسی داشته باشید.
@Component({...})
class MyComponent {
constructor(route: ActivatedRoute) {
const id: Observable<string> = route.params.pipe(map(p => p.id));
const url: Observable<string> = route.url.pipe(map(segments => segments.join('')));
// route.data includes both `data` and `resolve`
const user = route.data.pipe(map(d => d.user));
}
}
یک روتر باید با لیستی از تعاریف مسیر پیکربندی شود. شما روتر را با مسیرها از طریق روش «RouterModule.forRoot()» پیکربندی میکنید و نتیجه را به آرایه «واردات» AppModule اضافه میکنید.
const appRoutes: Routes = [ { path: 'todo/:id', component: TodoDetailComponent }, { path: 'todos', component: TodosListComponent, data: { title: 'Todos List' } }, { path: '', redirectTo: '/todos', pathMatch: 'full' }, { path: '**', component: PageNotFoundComponent } ]; @NgModule({ imports: [ RouterModule.forRoot( appRoutes, { enableTracing: true } // <-- debugging purposes only ) // other imports here ], // ... }) export class AppModule { }
اگر URL با هیچ یک از مسیرهای از پیش تعریف شده مطابقت نداشته باشد، باعث میشه روتر خطایی ایجاد کند و برنامه را خراب کند. در این حالت می تونین از مسیر wildcard استفاده کنید. یک مسیر عام دارای یک مسیر متشکل از دو ستاره برای مطابقت با هر URL است.
برای مثال، شما می تونین PageNotFoundComponent را برای مسیر wildcard به صورت زیر تعریف کنید
{ path: '**', component: PageNotFoundComponent }
نه، ماژول مسیریابی یک انتخاب طراحی است. وقتی پیکربندی ساده است، میتوانید از ماژول مسیریابی (مثلاً AppRoutingModule) صرفنظر کنید و پیکربندی مسیریابی را مستقیماً در ماژول همراه (مثلاً AppModule) ادغام کنید. اما زمانی توصیه میشه که پیکربندی پیچیده باشد و شامل خدمات تخصصی نگهبان و حل کننده باشد.
Angular Universal یک ماژول رندر سمت سرور برای برنامه های Angular در سناریوهای مختلف است. این یک پروژه جامعه محور است و در بسته @angular/platform-server موجود است. اخیرا Angular Universal با Angular CLI ادغام شده است.
Angular دو راه برای کامپایل برنامه شما ارائه می دهد.
به موقع (JIT)
پیش از زمان (AOT)
Just-in-Time (JIT) نوعی کامپایله که برنامه رو موقع اجرا تو مرورگر کامپایل میکنه. هنگامی که دستورات CLI ng build (فقط ساخت) یا ng serve (ساخت و ارائه به صورت لوکال) رو اجرا می کنین کامپایل JIT پیش فرض هستش. برای مثال، دستورات زیر برای کامپایل JIT استفاده میشه،
ng build
ng serve
Ahead-of-Time (AOT) نوعی کامپایله که برنامه رو تو build time کامپایل میکنه. برای کامپایل AOT، گزینه «--aot» رو با دستور ng build یا ng serve مثل کد زیر اضافه کنید.
ng build --aot
ng serve --aot
نکته: دستور ng build با --prod meta-flag ('ng build --prod') به طور پیش فرض با AOT کامپایل میشه.
کامپوننت ها و قالب های Angular رو نمی شه مستقیماً توی مرورگر استفاده کنیم. به همین دلیل برنامه های Angular قبل از اینکه بتونن تو مرورگر اجرا شن باید کامپایل بشن. برای مثال، در کامپایل AOT، هر دو کد Angular HTML و TypeScript در مرحله build قبل از اجرای مرورگر به کد جاوا اسکریپت قابل اجرا تبدیل مشن.
رندر سریعتر: مرورگر یک نسخه از پیش کامپایل شده برنامه رو دانلود میکنه. بنابراین می تونه برنامه رو بلافاصله بدون کامپایل کردن برنامه رندر کنه.
درخواست های async کمتر: قالب های HTML خارجی و برگه های سبک CSS رو تو برنامه جاوا اسکریپت قرار می ده که درخواست های جداگانه ajax رو حذف می کنه.
اندازه دانلود فریمورک Angular کوچکتر: نیازی به دانلود کامپایلر Angular ندارد. از این رو حجم برنامه رو کمترش میکنه.
تشخیص زودتر خطاهای template: خطاهای اتصال template رو در مرحله ساخت شناسایی و گزارش می کنه.
امنیت بهتر: قالب ها و اجزای HTML رو در جاوا اسکریپت کامپایل می کنه. بنابراین هیچ حمله injection اتفاق نمیوفته.
می تونیم کامپایل برنامه رو به دو روش کنترل کنیم
با ارائه گزینه های کامپایلر قالب در فایل tsconfig.json
با پیکربندی فراداده Angular با دکوراتورها
در Angular، باید metadata رو با محدودیت های کلی زیر نوشت:
نحو عبارت رو با در محدوده پشتیبانی شده از ویژگی های جاوا اسکریپت بنویسیم
کامپایلر فقط می تونه به نمادهایی که export ده ان ارجاع بده
فقط توابع پشتیبانی شده توسط کامپایلر رو فراخوانی کنیم
اعضای کلاس تزئین شده و محدود به داده ها باید عمومی باشن.
کامپایلر AOT تو سه فاز کار می کنه
تحلیل کد: کامپایلر نمایشی از منبع رو ثبت می کنه
تولید کد: تفسیر رو کنترل می کنه و همچنین محدودیت هایی رو در مورد آنچه تفسیر می کنه ایجاد می کنه.
اعتبار سنجی: در این مرحله، کامپایلر الگوی Angular از کامپایلر TypeScript برای اعتبارسنجی عبارات الزام آور در قالب ها استفاده می کنه.
نه arrow function یا توابع لامبدا رو نمیشه برای تخصیص مقادیر به ویژگی های دکوراتور استفاده کرد. برای مثال، کد زیر اعتباری نداره:
@Component({
providers: [{
provide: MyService, useFactory: () => getService()
}]
})
برای حل این مشکل کد بالا رو به شکل زیر تغییر میدیم:
function getService(){
return new MyService();
}
@Component({
providers: [{
provide: MyService, useFactory: getService
}]
})
اگه هنوز از تابع arrow استفاده می کنین یک گره خطا به جای تابع ایجاد می کنه. وقتی کامپایلر بعداً این گره رو تفسیر میکنه، یک خطا گزارش می کنه تا تابع فلش را به یک تابع صادر شده تبدیل کنه.
نکته: از Angular5 به بعد، کامپایلر به طور خودکار این بازنویسی رو در حین انتشار فایل js. انجام می ده.
فایل metadata.json رو میشه بهعنوان نموداری از ساختار کلی metadata های تزئینگر، که بهعنوان یک درخت نحو انتزاعی (AST) نشون داده میشه، در نظر گرفت. در طول مرحله تجزیه و تحلیل، جمعآورنده AOT ابردادههای ثبتشده در تزئینات Angular رو اسکن میکنه و اطلاعات metadata رو در فایلهای .metadata.json، یک عدد برای هر فایل .d.ts، خروجی میده.
خیر، گردآورنده AOT زیرمجموعه ای از (یا محدود) ویژگی های جاوا اسکریپت را درک می کنه. اگر عبارتی از نحو پشتیبانی نشده استفاده کنه گردآورنده یک گره خطا در فایل .metadata.json می نویسه. بعداً، کامپایلر در صورتی که برای تولید کد برنامه به اون تکه metadata ها نیاز داشته باشه خطایی رو گزارش میکنه.
کامپایلر فقط میتونه ارجاعات به نمادهای export شده در metadata رو حل کنه. جایی که برخی از اعضای غیرصادراتی هنگام تولید کد تا میشن. i.e Folding فرآیندی است که در آن گردآورنده یک عبارت رو در حین جمع آوری ارزیابی می کنه و نتیجه رو به جای عبارت اصلی در .metadata.json ثبت می کنه.
برای مثال، کامپایلر نمی تونه مرجع انتخابگر رو ارجاع بده چون export نشده
let selector = 'app-root';
@Component({
selector: selector
})
در انتخابگر درون خطی تا میشه
@Component({
selector: 'app-root'
})
به یاد داشته باشین که کامپایلر نمی تونه همه چیز رو fold کنه. برای مثال، عملگر گسترش بر روی آرایه ها، اشیاء ایجاد شده با استفاده از کلمات کلیدی جدید و فراخوانی تابع.
کامپایلر AOT از macro ها به شکل توابع یا متدهای ایستا پشتیبانی می کنه که عبارتی رو در یک عبارت بازگشتی واحد برمی گرداند.
برای مثال، یک تابع macro زیر رو در نظر بگیرین
export function wrapInArray<T>(value: T): T[] {
return [value];
}
می تونین از اون توی داخل metadata به عنوان یک عبارت استفاده کنین
@NgModule({
declarations: wrapInArray(TypicalComponent)
})
export class TypicalModule {}
کامپایلر با عبارات macro مثل نوشته شدن مستقیم رفتار میکنه
@NgModule({
declarations: [TypicalComponent]
})
export class TypicalModule {}
1. export class User { ... }
const prop = typeof User; // typeof is not valid in metadata
2. { provide: 'token', useValue: { [prop]: 'value' } }; // bracket notation is not valid in metadata
// ERROR let username: string; // neither exported nor initialized @Component({ selector: 'my-component', template: ... , providers: [ { provide: User, useValue: username } ] }) export class MyComponent {}
You can fix this by either exporting or initializing the value,
برای حل این مشکل یا میتونیم مقدار رو export بگیریم یا مقدار رو تعریف کنیم
export let username: string; // exported (or) let username = 'John'; // initialized
Function calls are not supported: کامپایلر در حال حاضر از عبارات تابع یا توابع لامبدا پشتیبانی نمی کنه. برای مثال، نمیتوانید useFactory ارائهدهنده را روی یک تابع ناشناس یا تابع فلش مانند زیر تنظیم کنید.
providers: [ { provide: MyStrategy, useFactory: function() { ... } }, { provide: OtherStrategy, useFactory: () => { ... } } ]
میتونیم این مشکل رو با تابع export شده حل کنیم
export function myStrategy() { ... } export function otherStrategy() { ... } ... // metadata providers: [ { provide: MyStrategy, useFactory: myStrategy }, { provide: OtherStrategy, useFactory: otherStrategy }, ]
متغیر تخریب شده یا ثابت پشتیبانی نمیشه: کامپایلر ارجاع به متغیرهای اختصاص داده شده توسط ساختارشکنی رو پشتیبانی نمی کنه. برای مثال، ما نمی تونیم چیزی شبیه به این بتویسیم:
import { user } from './user'; // destructured assignment to name and age const {name, age} = user; ... //metadata providers: [ {provide: Name, useValue: name}, {provide: Age, useValue: age}, ]
ما می تونیم این مشکل رو با مقادیر غیر تخریب شده برطرف کنیم
import { user } from './user'; ... //metadata providers: [ {provide: Name, useValue: user.name}, {provide: Age, useValue: user.age}, ]
metadata rewriting فرآیندای که تو اون کامپایلر عبارتی رو که فیلدهایی مانند useClass، useValue، useFactory و داده رو مقداردهی اولیه می کنه، به یک متغیر export شده تبدیل می کنه که جایگزین عبارت میشه. به یاد داشته باشیم که کامپایلر این بازنویسی رو در حین انتشار فایل js انجام می ده اما در فایل های تعریف (فایل .d.ts) این کارو انجام نمی ده.
Angular Compiler از وراثت پیکربندی از طریق Extend در tsconfig.json در angularCompilerOptions پشتیبانی میکنه. برای مثال، پیکربندی از فایل پایه (برای مثال، tsconfig.base.json) ابتدا بارگیری میشه، سپس توسط اونایی که تو فایل پیکربندی ارثی هستند، لغو میشن.
{ "extends": "../tsconfig.base.json", "compilerOptions": { "experimentalDecorators": true, ... }, "angularCompilerOptions": { "fullTemplateTypeCheck": true, "preserveWhitespaces": true, ... } }
گزینه های کامپایلر قالب انگولاری به عنوان اعضای شی angularCompilerOptions در فایل tsconfig.json مشخص شده اند. این گزینه ها در مجاورت گزینه های کامپایلر typescript مشخص میشن.
{ "compilerOptions": { "experimentalDecorators": true, ... }, "angularCompilerOptions": { "fullTemplateTypeCheck": true, "preserveWhitespaces": true, ... } }
شما می تونین صریحاً با افزودن گزینه کامپایلر fullTemplateTypeCheck در "angularCompilerOptions" tsconfig.json پروژه، اعتبار سنجی عبارت binding رو فعال کنید. وقتی که یه خطای نوع در عبارت اتصال الگو تشخیص داده میشه، پیام های خطا تولید میکنه.
برای مثال، جزء زیر را در نظر بگیرید:
@Component({ selector: 'my-component', template: '{{user.contacts.email}}' }) class MyComponent { user?: User; }
این باعث ایجاد خطای زیر میشه:
my.component.ts.MyComponent.html(1,1): : Property 'contacts' does not exist on type 'User'. Did you mean 'contact'?
می تونین بررسی نوع عبارت binding را با استفاده از تابع cast نوع $any() غیرفعال کنید (با احاطه کردن عبارت). در مثال زیر، خطای Property contacts does not exist با فرستادن کاربر به هر نوع اجباری حذف شده.
template: '{{ $any(user).contacts.email }}'
تابع $any() cast هم با این کار میکنه تا امکان دسترسی به اعضای اعلام نشده کامپوننت را فراهم کنه.
template: '{{ $any(this).contacts.email }}'
برای سرکوب خطای Object is assibly 'undefined' می تونین از عملگر اظهاری نوع غیر تهی استفاده کنید. در مثال زیر، ویژگی های کاربر و مخاطب همیشه با هم تنظیم میشن، به این معنی که اگر کاربر غیر تهی باشد، مخاطب همیشه غیر تهی است. خطا در مثال با استفاده از contact!.email سرکوب شده است.
@Component({ selector: 'my-component', template: '<span *ngIf="user"> {{user.name}} contacted through {{contact!.email}} </span>' }) class MyComponent { user?: User; contact?: Contact; setData(user: User, contact: Contact) { this.user = user; this.contact = contact; } }
عبارت مورد استفاده در یک دستورالعمل ngIf برای محدود کردن اتحادیه های نوع در کامپایلر الگوی Angular مشابه عبارت if در تایپ اسکریپت استفاده میشه. بنابراین *ngIf به کامپایلر typeScript اجازه می دهد استنباط کنه که داده های مورد استفاده در عبارت binding هرگز تعریف نشده نخواهد بود.
@Component({ selector: 'my-component', template: '<span *ngIf="user"> {{user.contact.email}} </span>' }) class MyComponent { user?: User; }
بخش وابستگی های package.json با در یک برنامه انگولاری را می توان به صورت زیر تقسیم کرد:
بسته های انگولاری: هسته انگولاری و ماژول های اختیاری. نام بسته آنها @angular/ شروع میشه.
بسته های پشتیبانی: کتابخونه های شخص ثالثی که برای اجرای برنامه های Angular باید وجود داشته باشند.
بسته های Polyfill: Polyfill شکاف ها را در پیاده سازی جاوا اسکریپت مرورگر وصل میکنه.
Zone یه زمینه اجراییه که تو تمام وظایف ناهمگام باقی می مونه. وقتی که عملیات جاوا اسکریپت بومی رویدادها رو افزایش می ده Angular برای اجرای فرآیندهای تشخیص تغییر Angular به zone.js متکی است.
خدمات، pipe ها و دستورالعملهای مورد نیاز معمولاً توسط ماژول @angular/common ارائه شده. جدا از این HttpClientModule در زیر angular/common/http@ وجود داره.
Codelyzer مجموعه ای از قوانین tslint را برای تجزیه و تحلیل کد استاتیک پروژه های Angular TypeScript ارائه می دهد. می تونین تحلیلگر کد استاتیک را روی برنامه های وب، NativeScript، Ionic و غیره اجرا کنید. Angular CLI از این پشتیبانی میکنه و می توان از آن به صورت زیر استفاده کرد.
ng new codelyzer ng lint
سیستم انیمیشن Angular بر اساس عملکرد CSS ساخته شده است تا هر خاصیتی را که مرورگر آن را قابل انیمیشن می داند، متحرک کنه. این ویژگیها شامل موقعیتها، اندازهها، تبدیلها، رنگها، حاشیهها و غیره است. ماژولهای Angular برای انیمیشنها @angular/animations و @angular/platform-browser هستند و این وابستگیها به طور خودکار به پروژه شما اضافه میشوند. شما یک پروژه با استفاده از Angular CLI ایجاد می کنید.
برای پیاده سازی انیمیشن در پروژه انگولاری خود باید مراحل زیر را دنبال کنید.
Enabling the animations module: BrowserAnimationsModule رو import کنین تا قابلیتهای انیمیشن را به ماژول برنامه Angular root خود اضافه کنین (برای مثال، src/app/app.module.ts).
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; @NgModule({ imports: [ BrowserModule, BrowserAnimationsModule ], declarations: [ ], bootstrap: [ ] }) export class AppModule { }
Importing animation functions into component files: توابع انیمیشن مورد نیازتون رو از @angular/animations در فایلهای مؤلفه import کنین (برای مثال، src/app/app.component.ts).
import { trigger, state, style, animate, transition, // ... } from '@angular/animations';
Adding the animation metadata property: یک ویژگی metadata به نام animations اضافه کنین: در دکوراتور @Component() در فایل های کامپوننت (برای مثال src/app/app.component.ts)
@Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.css'],
animations: [
// animation triggers go here
]
})
تابع state() Angular برای تعریف حالت های مختلف برای فراخوانی در پایان هر انتقال استفاده میشه. این تابع دو آرگومان می گیرد: یک نام منحصر به فرد مانند open یا بسته و یک تابع style().
برای مثال، می تونین یک تابع حالت باز بنویسین
state('open', style({
height: '300px',
opacity: 0.5,
backgroundColor: 'blue'
})),
تابع style برای تعریف مجموعهای از سبکها برای مرتبط کردن با یک نام وضعیت استفاده میشه. برای تنظیم ویژگی های سبک CSS باید از آن به همراه تابع state() استفاده کنید. برای مثال، در حالت بسته، دکمه دارای ارتفاع 100 پیکسل، کدورت 0.8 و رنگ زمینه سبز است.
state('close', style({
height: '100px',
opacity: 0.8,
backgroundColor: 'green'
})),
نکته: The style attributes must be in camelCase.
انیمیشنهای Angular روشی قدرتمند برای پیادهسازی انیمیشنهای پیچیده و قانعکننده برای اپلیکیشن وب تک صفحهای Angular شما هستن.
import { Component, OnInit, Input } from '@angular/core';
import { trigger, state, style, animate, transition } from '@angular/animations';
@Component({
selector: 'app-animate',
templateUrl: `<div [@changeState]="currentState" class="myblock mx-auto"></div>`,
styleUrls: `.myblock {
background-color: green;
width: 300px;
height: 250px;
border-radius: 5px;
margin: 5rem;
}`,
animations: [
trigger('changeState', [
state('state1', style({
backgroundColor: 'green',
transform: 'scale(1)'
})),
state('state2', style({
backgroundColor: 'red',
transform: 'scale(1.5)'
})),
transition('*=>state1', animate('300ms')),
transition('*=>state2', animate('2000ms'))
])
]
})
export class AnimateComponent implements OnInit {
@Input() currentState;
constructor() { }
ngOnInit() {
}
}
تابع transition انیمیشن برای تعیین تغییراتی که بین یک حالت و حالت دیگر در یک دوره زمانی رخ می دهد استفاده میشه. دو آرگومان را می پذیرد: آرگومان اول عبارتی را می پذیرد که جهت بین دو حالت گذار را مشخص میکنه و آرگومان دوم تابع animate() را می پذیرد.
یک مثال انتقال حالت از باز به بسته با انتقال نیم ثانیه بین حالت ها رو در نظر بگیریم.
transition('open => closed', [
animate('500ms')
]),
با استفاده از DomSanitizer میتوانیم Html، Style، Script، Url پویا رو وارد کنیم.
</span>
import { Component, OnInit } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
@Component({
selector: 'my-app',
template: `
<div [innerHtml]="htmlSnippet"></div>
`,
})
export class App {
constructor(protected sanitizer: DomSanitizer) {}
htmlSnippet: string = this.sanitizer.bypassSecurityTrustScript("<script>safeCode()</script>");
}
Service Worker یک اسکریپته که تو مرورگر وب اجرا میشه و حافظه پنهان یک برنامه رو مدیریت میکنه. با شروع از نسخه 5.0.0، Angular با یک service worker ارائه میشه. Angular service worker برای بهینه سازی تجربه کاربر نهایی از استفاده از یک برنامه کاربردی از طریق اتصال شبکه کنه یا غیرقابل اعتماد طراحی شده در حالی که خطرات ارائه محتوای قدیمی رو هم به حداقل می رسونه.
یک برنامه را مانند نصب یک برنامه بومی کش میکنه
یک برنامه در حال اجرا با همان نسخه از همه فایل ها بدون هیچ فایل ناسازگاری به کار خود ادامه می دهد
هنگامی که برنامه را به روز می کنید، آخرین نسخه کاملاً کش شده را بارگیری میکنه
هنگامی که تغییرات منتشر میشه، بلافاصله در پس زمینه به روز میشه
Service Workers پهنای باند را با بارگیری منابع صرفه جویی میکنه که فقط زمانی که آنها تغییر کرده اند.
تزریق وابستگی یک جزء مشترک در AngularJS و Angular است، اما تفاوتهای کلیدی بین این دو فریمورک در نحوه عملکرد واقعی آن وجود دارد.
AngularJS | Angular |
---|---|
توکن های تزریق وابستگی همیشه رشته ای هستند | توکن ها می تونن انواع مختلفی داشته باشند. آنها اغلب کلاس هستند و گاهی اوقات می تونن رشته باشند. |
دقیقاً یک انژکتور وجود دارد حتی اگر یک برنامه کاربردی چند ماژول است | یک سلسله مراتب درختی از انژکتورها وجود دارد که برای هر جزء یک انژکتور ریشه و یک انژکتور اضافی وجود دارد. |
Angular Ivy یک موتور رندر جدید برای Angular است. میتوانید نسخه پیشنمایش Ivy را از نسخه 8 Angular انتخاب کنید.
با استفاده از پرچم --enable-ivy با دستور ng new می تونین ivy را در یک پروژه جدید فعال کنید
ng new ivy-demo-app --enable-ivy
میتوانید با افزودن گزینه «enableIvy» در «angularCompilerOptions» در «tsconfig.app.json» پروژه خود، آن را به یک پروژه موجود اضافه کنید.
{ "compilerOptions": { ... }, "angularCompilerOptions": { "enableIvy": true } }
می تونین با پیش نمایش Ivy انتظار ویژگی های زیر را داشته باشید.
کد تولید شده که خواندن و اشکال زدایی آن در زمان اجرا آسان تر است
زمان بازسازی سریعتر
بهبود اندازه محموله
بررسی نوع قالب بهبود یافته است
بله، این یک پیکربندی توصیه شده است. همچنین، کامپایل AOT با Ivy سریعتر است. بنابراین باید گزینه های ساخت پیش فرض (با در angular.json) را برای پروژه خود تنظیم کنید تا همیشه از کامپایل AOT استفاده کنه.
{
"projects": {
"my-project": {
"architect": {
"build": {
"options": {
...
"aot": true,
}
}
}
}
}
}
سرویس زبان Angular راهی برای دریافت تکمیل، خطا، نکات و پیمایش در قالبهای Angular شما است، چه خارجی در یک فایل HTML باشند و چه در حاشیهنویسی/تزیینات در یک رشته تعبیه شده باشند. این قابلیت را دارد که به طور خودکار تشخیص دهد که شما در حال باز کردن یک فایل Angular هستید، فایل tsconfig.json شما را می خواند، تمام الگوهایی را که در برنامه خود دارید پیدا میکنه و سپس تمام خدمات زبان را ارائه می دهد.
با دستور npm زیر می تونین Angular Language Service را در پروژه خود نصب کنید.
npm install --save-dev @angular/language-service
پس از آن موارد زیر را به بخش "compilerOptions" tsconfig.json پروژه خود اضافه کنید
"plugins": [
{"name": "@angular/language-service"}
]
نکته: خدمات تکمیل و تشخیص فقط برای فایل های .ts کار میکنه. برای پشتیبانی از فایل های HTML باید از افزونه های سفارشی استفاده کنید.
بله، سرویس زبان Angular در حال حاضر برای Visual Studio Code و WebStorm IDE در دسترس است. شما باید سرویس زبان انگولاری را با استفاده از افزونه و devDependency نصب کنید. در ویرایشگر sublime، باید تایپ اسکریپتی را نصب کنید که دارای مدل پلاگین سرویس زبان است.
اساساً 3 ویژگی اصلی توسط Angular Language Service ارائه شده است.
Autocompletion: تکمیل خودکار می تونه زمان توسعه شما را با ارائه امکانات و نکات متنی در حین تایپ در درون یابی و عناصر، سرعت بخشد.
Error checking: همچنین می تونه به شما در مورد اشتباهات کدتان هشدار دهد.
Navigation: ناوبری به شما این امکان را می دهد که یک کامپوننت، دایرکتیو، ماژول را نگه دارید و سپس F12 را کلیک کرده و فشار دهید تا مستقیماً به تعریف آن بروید.
شما می تونین web worker را در هر جایی از برنامه خود اضافه کنید. برای مثال، اگر فایل حاوی محاسبات گران قیمت شما «src/app/app.component.ts» است، میتوانید با استفاده از دستور «ng generate web-worker app» یک Web Worker اضافه کنید که «src/app/app» را ایجاد میکند. فایل web worker worker.ts. این دستور اقدامات زیر را انجام می دهد
پروژه خود را برای استفاده از Web Workers پیکربندی کنید
app.worker.ts را برای دریافت پیام اضافه میکنه
addEventListener('message', ({ data }) => {
const response = `worker response to ${data}`;
postMessage(response);
});
فایل کامپوننت «app.component.ts» با فایل web worker بهروزرسانی شد
if (typeof Worker !== 'undefined') { // Create a new const worker = new Worker('./app.worker', { type: 'module' }); worker.onmessage = ({ data }) => { console.log('page got message: $\{data\}'); }; worker.postMessage('hello'); } else { // Web Workers are not supported in this environment. }
نکته: ممکنه نیاز داشته باشید که کد اولیه web worker داربست خود را برای ارسال پیام به و از آن تغییر دهید.
هنگام استفاده از Web Workers در پروژه های Angular باید دو نکته مهم را به خاطر بسپارید:
1.برخی از محیطها یا پلتفرمها (مانند @angular/platform-server) که در رندر سمت سرور استفاده میشوند، از Web Workers پشتیبانی نمیکنند. در این مورد باید مکانیزم بازگشتی برای انجام محاسبات برای کار در این محیط ها فراهم کنید.
2. اجرای Angular در وبکار با استفاده از «@angular/platform-webworker» هنوز در Angular CLI پشتیبانی نمیشه.
در Angular8، CLI Builder API پایدار است و در دسترس توسعه دهندگانی است که می خواهند «Angular CLI» را با افزودن یا تغییر دستورات سفارشی کنند. برای مثال، میتوانید یک سازنده را برای انجام یک کار کاملاً جدید یا تغییر اینکه کدوم ابزار شخص ثالث توسط یک دستور موجود استفاده میشه، فراهم کنید.
یک تابع سازنده یعنی تابعی که از "API Architect" برای انجام یک فرآیند پیچیده مانند "build" یا "test" استفاده میکنه. کد سازنده در یک بسته npm تعریف شده است. برای مثال، BrowserBuilder یک ساخت بسته وب را برای یک هدف مرورگر اجرا میکنه و KarmaBuilder سرور Karma را راه اندازی میکنه و یک بسته وب را برای آزمایش های واحد اجرا میکنه.
دستور Angular CLI «ng run» برای فراخوانی سازنده ای با پیکربندی هدف خاص استفاده میشه. فایل پیکربندی فضای کاری، «angular.json»، حاوی تنظیمات پیشفرض برای سازندههای داخلی است.
پوسته برنامه راهی برای ارائه بخشی از برنامه شما از طریق یک مسیر در زمان ساخت است. این برای اولین بار رنگ آمیزی برنامه شما که به سرعت ظاهر میشه مفید است چون مرورگر می تونه HTML و CSS ایستا را بدون نیاز به مقداردهی اولیه جاوا اسکریپت ارائه دهد. شما می تونین با استفاده از Angular CLI که یک پوسته برنامه برای اجرای سمت سرور برنامه شما ایجاد میکنه، به این هدف برسید.
ng generate appShell [options] (or)
ng g appShell [options]
Angular از قراردادهای بزرگ برای تشخیص نام انواع مختلف استفاده میکنه. Angular لیستی از انواع موارد زیر را دنبال میکنه.
camelCase : نمادها، ویژگیها، روشها، نام pipe ها، انتخابکنندههای دستورالعمل غیرمولفه، ثابتها از حروف کوچک در حرف اول آیتم استفاده میکنند. برای مثال، "selectedUser"
UpperCamelCase (or PascalCase): نام کلاسها، از جمله کلاسهایی که اجزا، رابطها، NgModules، دستورالعملها و pipe ها را تعریف میکنند، از حروف بزرگ در حرف اول آیتم استفاده میکنند.
dash-case (or "kebab-case"): در قسمت توصیفی نام فایل ها، انتخابگرهای مؤلفه از خط تیره بین کلمات استفاده میشه. برای مثال، "app-user-list".
UPPER_UNDERSCORE_CASE: همه ثابت ها از حروف بزرگ مرتبط با خط زیر استفاده می کنند. برای مثال، "NUMBER_OF_USERS".
دکوراتور کلاس، دکوراتوری است که بلافاصله قبل از تعریف کلاس ظاهر میشه، که کلاس را از نوع معین اعلام میکنه و ابرداده مناسب برای نوع را فراهم میکنه.
لیست زیر از دکوراتورها در زیر کلاس دکوراتورها آمده است:
@Component()
@Directive()
@Pipe()
@Injectable()
@NgModule()
دکوراتورهای فیلد کلاس عباراتی هستند که بلافاصله قبل از یک فیلد در تعریف کلاس اعلام میشن که نوع آن فیلد را مشخص میکنه. برخی از نمونه ها عبارتند از: @input و @output،
@Input() myProperty;
@Output() myEvent = new EventEmitter();
Declarable یک نوع کلاس است که می تونین آن را به لیست اعلانات یک NgModule اضافه کنید. انواع کلاس ها مانند کامپوننت ها، دستورالعمل ها و لوله ها را می توان در ماژول اعلام کرد. ساختار اعلامیه ها به این صورت خواهد بود
declarations: [
YourComponent,
YourPipe,
YourDirective
],
کلاس های زیر نباید تعریف شوند،
کلاسی که قبلاً در NgModule دیگری اعلام شده است
کلاس های Ngmodule
کلاس های خدماتی
کلاس های کمکی
توکن DI یک توکن جستجوی مرتبط با ارائه دهنده وابستگی در سیستم تزریق وابستگی است. انژکتور یک نقشه ارائه دهنده توکن داخلی دارد که در صورت درخواست وابستگی به آن ارجاع می دهد و رمز DI کلید نقشه است. بیایید استفاده از DI Token را مثال بزنیم،
const BASE_URL = new InjectionToken<string>('BaseUrl');
const injector =
Injector.create({providers: [{provide: BASE_URL, useValue: 'http://some-domain.com'}]});
const url = injector.get(BASE_URL);
یک زبان دامنه خاص (DSL) یک زبان کامپیوتری است که برای یک دامنه کاربردی خاص تخصصی شده است. Angular زبان مخصوص دامنه (DSL) خود را دارد که به ما اجازه میدهد تا سینتکس html مانند خاص Angular را در بالای html معمولی بنویسیم. این کامپایلر خود را دارد که این نحو را به html کامپایل میکنه که مرورگر بتونه آن را درک کنه. این DSL در NgModules مانند انیمیشن ها، فرم ها و مسیریابی و ناوبری تعریف شده است.
اساساً شما 3 نحو اصلی را در Angular DSL خواهید دید.
()
: برای رویدادهای خروجی و DOM استفاده میشه.
[]
: برای ورودی و ویژگی های خاص عنصر DOM استفاده میشه.
*
: دستورالعمل های ساختاری (*ngFor یا *ngIf) ساختار DOM را تحت تاثیر قرار می دهد/تغییر می دهد.
یک موضوع RxJS نوع خاصی از Observable است که اجازه میدهد مقادیر برای بسیاری از Observerها چندپخشی شوند. در حالی که مشاهده پذیرهای ساده یکپارچه هستند (هر مشاهده کننده مشترک دارای اجرای مستقل از Observable است)، سوژه ها چندپخشی هستند.
یک موضوع مانند یک مشاهده پذیر است، اما می تونه برای بسیاری از مشاهده کنندگان چندپخش شود. سوژه ها مانند EventEmitters هستند: آنها یک رجیستری از شنوندگان زیادی را نگهداری می کنند.
import { Subject } from 'rxjs'; const subject = new Subject<number>(); subject.subscribe({ next: (v) => console.log(`observerA: ${v}`) }); subject.subscribe({ next: (v) => console.log(`observerB: ${v}`) }); subject.next(1); subject.next(2);
Bazel یک ابزار ساخت قدرتمند است که توسط گوگل توسعه یافته و به طور گسترده مورد استفاده قرار می گیرد و می تونه وابستگی های بین بسته های مختلف و اهداف ساخت را پیگیری کنه. در Angular8 می تونین برنامه CLI خود را با Bazel بسازید. **نکته:** خود فریم ورک Angular با Bazel ساخته شده است. **[فهرست](#فهرست)**
این امکان را ایجاد میکنه که با همان ابزار بک اند و جلویی شما را بسازید
ساخت افزایشی و تست
این امکان را ایجاد میکنه که از راه دور ساخت و حافظه پنهان در یک مزرعه ساخت.
**[فهرست](#فهرست)**
بسته @angular/bazel سازنده ای را ارائه می دهد که به Angular CLI اجازه می دهد از Bazel به عنوان ابزار ساخت استفاده کنه.
Use in an existing applciation: @angular/bazel را با استفاده از CLI اضافه کنید
ng add @angular/bazel
Use in a new application: بسته را نصب کنید و برنامه را با گزینه مجموعه ایجاد کنید
npm install -g @angular/bazel
ng new --collection=@angular/bazel
وقتی از دستورات ng build و ng serve استفاده می کنید، Bazel در پشت صحنه استفاده میشه و نتایج را در پوشه dist/bin خروجی می دهد.
گاهی اوقات ممکنه بخواهید سازنده Angular CLI را دور بزنید و Bazel را مستقیماً با استفاده از Bazel CLI اجرا کنید. می تونین با استفاده از بسته @bazel/bazel npm آن را به صورت سراسری نصب کنید. یعنی Bazel CLI در بسته @bazel/bazel موجود است. بعد از اینکه بتوانید دستورات رایج زیر را اعمال کنید،
bazel build [targets] // Compile the default output artifacts of the given targets.
bazel test [targets] // Run the tests with *_test targets found in the pattern.
bazel run [target]: Compile the program represented by target and then run it.
پلتفرم زمینه ای است که یک برنامه Angular در آن اجرا میشه. رایج ترین پلت فرم برای برنامه های Angular یک مرورگر وب است، اما همچنین می تونه یک سیستم عامل برای یک دستگاه تلفن همراه یا یک وب سرور باشد. Runtime-Platform توسط بستههای angular/platform-*@ ارائه میشه و این بستهها به برنامههایی که از «@angular/core» و «@angular/common» استفاده میکنند اجازه میدهند در محیطهای مختلف اجرا شوند.
برای مثال، Angular می تونه به عنوان چارچوب مستقل از پلت فرم در محیط های مختلف استفاده شود، برای مثال،
در حین اجرا در مرورگر، از بسته پلتفرم-مرورگر استفاده میکنه.
هنگامی که SSR (رندر سمت سرور) استفاده میشه، از بسته «پلتفرم-سرور» برای ارائه اجرای وب سرور استفاده میکنه.
اگر چندین ماژول یک ماژول را وارد کنه، angular آن را فقط یک بار ارزیابی میکنه (وقتی اولین بار با ماژول روبرو میشه). از این شرط پیروی میکنه حتی ماژول در هر سطحی در سلسله مراتب NgModules وارد شده ظاهر میشه.
برای دسترسی مستقیم به عناصر موجود در نما می تونین از دستورالعمل @ViewChild
استفاده کنید. بیایید عنصر ورودی را با یک مرجع بگیریم،
<input #uname>
و view child Directive را تعریف کرده و در قلاب چرخه حیات ngAfterViewInit به آن دسترسی پیدا کنید
@ViewChild('uname') input;
ngAfterViewInit() {
console.log(this.input.nativeElement.value);
}
در Angular7 می تونین برای تشخیص تغییرات در روتر مشترک شوید. اشتراک رویدادهای روتر به شرح زیر خواهد بود:
this.router.events.subscribe((event: Event) => {})
بیایید یک جزء ساده برای تشخیص تغییرات روتر در نظر بگیریم
import { Component } from '@angular/core'; import { Router, Event, NavigationStart, NavigationEnd, NavigationError } from '@angular/router'; @Component({ selector: 'app-root', template: `<router-outlet></router-outlet>` }) export class AppComponent { constructor(private router: Router) { this.router.events.subscribe((event: Event) => { if (event instanceof NavigationStart) { // Show loading indicator and perform an action } if (event instanceof NavigationEnd) { // Hide loading indicator and perform an action } if (event instanceof NavigationError) { // Hide loading indicator and perform an action console.log(event.error); // It logs an error for debugging } }); } }
میتوانید مستقیماً نقشه شی را برای مشتری http ارسال کنید یا کلاس HttpHeaders را برای تهیه هدرها ایجاد کنید.
constructor(private _http: HttpClient) {} this._http.get('someUrl',{ headers: {'header1':'value1','header2':'value2'} }); (or) let headers = new HttpHeaders().set('header1', headerValue1); // create header object headers = headers.append('header2', headerValue2); // add a new header, creating a new object headers = headers.append('header3', headerValue3); // add another header let params = new HttpParams().set('param1', value1); // create params object params = params.append('param2', value2); // add a new param, creating a new object params = params.append('param3', value3); // add another param return this._http.get<any[]>('someUrl', { headers: headers, params: params })
از انتشار Angular8 به بعد، برنامهها با استفاده از استراتژی بارگذاری تفاضلی از CLI ساخته میشن تا دو باندل جداگانه به عنوان بخشی از برنامه مستقر شما بسازنس.
اولین ساخت شامل نحو ES2015 هس که از مزیت پشتیبانی داخلی در مرورگرهای مدرن بهره میبرد، plyfill ها کمتری ارسال میکند و منجر به اندازه بستهای کوچکتر میشه.
ساخت دوم شامل نحو قدیمی ES5 برای پشتیبانی از مرورگرهای قدیمی با تمام plyfill های لازمه. اما این باعث میشه اندازه بسته بزرگتر شه.
نکته: این استراتژی برای پشتیبانی از چندین مرورگر استفاده میشه، اما فقط کد مورد نیاز مرورگر را بارگیری میکنه.
بله، Angular 8 از واردات پویا در پیکربندی روتر پشتیبانی میکنه. برای مثال، میتونین از دستور import برای lazy loading ماژول با استفاده از روش «loadChildren» استفاده کنین و توسط IDEها (VSCode و WebStorm)، بسته وب و غیره قابل درک است.
قبلاً به صورت زیر نوشته شده بودید تا ماژول ویژگی رو با lazy loading کنین. به اشتباه، اگر در نام ماژول اشتباه تایپی داشته باشید، همچنان رشته رو میپذیرد و موقع build خطا میده.
{path: ‘user’, loadChildren: ‘./users/user.module#UserModulee’},
این مشکل با استفاده از واردات پویا حل میشه و IDE ها می تونن اون رو در طول زمان کامپایل پیدا کنن.
{path: ‘user’, loadChildren: () => import(‘./users/user.module’).then(m => m.UserModule)};
Lazy loading یکی از کاربردی ترین مفاهیم Angular Routing هس. این به ما کمک میکنه تا به جای دانلود همه چیز در یک بسته بزرگ، صفحات وب رو به صورت تکه ای دانلود کنیم. برای Lazy loading با بارگیری async ماژول ویژگی برای مسیریابی هر زمان که لازم باشد با استفاده از ویژگی «loadChildren» استفاده میشه. بیایید هر دو ماژول ویژگی «مشتری» و «سفارش» رو مثل زیر بارگیری کنیم.
const routes: Routes = [
{
path: 'customers',
loadChildren: () => import('./customers/customers.module').then(module => module.CustomersModule)
},
{
path: 'orders',
loadChildren: () => import('./orders/orders.module').then(module => module.OrdersModule)
},
{
path: '',
redirectTo: '',
pathMatch: 'full'
}
];
نسخه Angular 8.0 API های Workspace را معرفی میکنه تا خواندن و اصلاح فایل angular.json را برای توسعه دهندگان به جای تغییر دستی آسان تر کنه. در حال حاضر، تنها فرمت Storage3 پشتیبانی شده، فرمت مبتنی بر JSON است که توسط Angular CLI استفاده میشه. میتوانید گزینه بهینهسازی را برای build target به صورت زیر فعال یا اضافه کنید.
import { NodeJsSyncHost } from '@angular-devkit/core/node';
import { workspaces } from '@angular-devkit/core';
async function addBuildTargetOption() {
const host = workspaces.createWorkspaceHost(new NodeJsSyncHost());
const workspace = await workspaces.readWorkspace('path/to/workspace/directory/', host);
const project = workspace.projects.get('my-app');
if (!project) {
throw new Error('my-app does not exist');
}
const buildTarget = project.targets.get('build');
if (!buildTarget) {
throw new Error('build target does not exist');
}
buildTarget.options.optimization = true;
await workspaces.writeWorkspace(workspace, host);
}
addBuildTargetOption();
ارتقای Angular با استفاده از دستور Angular CLI «ng update» همانطور که در زیر ذکر شده است بسیار ساده تر است. برای مثال، اگر از Angular 7 به 8 ارتقا دهید، وارد کردن مسیر لود شده lazy شما به صورت خودکار به نحو واردات جدید منتقل میشه.
$ ng update @angular/cli @angular/core
Angular Material مجموعه ای از اجزای طراحی متریال برای فریم ورک Angular است که از مشخصات طراحی متریال پیروی میکنه. با استفاده از Angular Material می تونین Material Design را به راحتی اعمال کنید. نصب را می توان از طریق npm یا نخ انجام داد،
npm install --save @angular/material @angular/cdk @angular/animations (OR) yarn add @angular/material @angular/cdk @angular/animations
از دو نسخه اخیر همه مرورگرهای اصلی پشتیبانی میکنه. آخرین نسخه متریال Angular 8.1.1 است
اگر از سرویس «location» را به سرویس «Location» در Angular میگذارد. بیایید این ماژول را مانند زیر به AppModule اضافه کنیم،
// Other imports ...
import { LocationUpgradeModule } from '@angular/common/upgrade';
@NgModule({
imports: [
// Other NgModule imports...
LocationUpgradeModule.config()
]
})
export class AppModule {}
NgUpgrade یک کتابخونه است که توسط تیم Angular گردآوری شده است که می تونین از آن در برنامه های خود برای ترکیب و مطابقت اجزای AngularJS و Angular و پل زدن سیستم های تزریق وابستگی AngularJS و Angular استفاده کنید.
Angular CLI همه موارد مورد نیاز را با چارچوب تست Jasmine دانلود و نصب میکنه. برای دیدن نتایج آزمون فقط باید «ng test» را اجرا کنید. بهطور پیشفرض، این دستور برنامه را در حالت تماشا میسازد و «Karma test runner» را راهاندازی میکند. خروجی نتایج آزمون به صورت زیر خواهد بود:
10% building modules 1/1 modules 0 active ...INFO [karma]: Karma v1.7.1 server started at http://0.0.0.0:9876/ ...INFO [launcher]: Launching browser Chrome ... ...INFO [launcher]: Starting browser Chrome ...INFO [Chrome ...]: Connected on socket ... Chrome ...: Executed 3 of 3 SUCCESS (0.135 secs / 0.205 secs)
نکته: یک مرورگر کروم نیز باز میشه و خروجی تست را در "Jasmine HTML Reporter" نمایش می دهد.
Angular CLI به طور رسمی از polyfills پشتیبانی میکنه. هنگامی که یک پروژه جدید با دستور ng new ایجاد می کنید، یک فایل پیکربندی src/polyfills.ts
به عنوان بخشی از پوشه پروژه شما ایجاد میشه. این فایل شامل اجباری و بسیاری از polyfill های اختیاری به عنوان دستورهای واردات جاوا اسکریپت است. بیایید پلی پرها را دسته بندی کنیم،
Mandatory polyfills: هنگامی که پروژه خود را با دستور ng new و دستورهای import مربوطه فعال در فایل 'src/polyfills.ts' فعال می کنید، اینها به طور خودکار نصب میشن.
npm install --save web-animations-js
و دستور import را در فایل polyfill ایجاد کنید.
import 'web-animations-js';
میتوانید ApplicationRef یا NgZone یا ChangeDetectorRef را به کامپوننت خود تزریق کنید و از روشهای خاص زیر برای شروع تشخیص تغییر در Angular استفاده کنید. یعنی 3 راه ممکن وجود دارد،
ApplicationRef.tick(): از این روش برای پردازش صریح تشخیص تغییر و عوارض جانبی آن استفاده کنید. درخت کامپوننت کامل را بررسی میکنه.
NgZone.run(callback): عملکرد برگشت به تماس را در داخل منطقه Angular ارزیابی میکنه.
ChangeDetectorRef.detectChanges(): فقط اجزاء و بچه ها را تشخیص می دهد.
نسخه های مختلفی از فریم ورک Angular وجود دارد. بیایید ویژگی های تمام نسخه های مختلف را ببینیم،
Angular 1 (AngularJS) اولین فریم ورک انگولاری است که در سال 2010 منتشر شد.
AngularJS برای دستگاه های تلفن همراه ساخته نشده است.
بر پایه کنترلرهایی با معماری MVC ساخته شده است.
Angular 2 در سال 2016 منتشر شد. Angular 2 بازنویسی کامل نسخه Angular1 است.
مشکلات عملکرد نسخه Angular 1 در نسخه Angular 2 برطرف شده است.
Angular 2 برخلاف نسخه Angular 1 از ابتدا برای دستگاه های تلفن همراه ساخته شده است.
Angular 2 مبتنی بر کامپوننت است.
نسخه های مختلف بسته در Angular 2 به شرح زیر است:
@angular/core نسخه 2.3.0
@angular/compiler نسخه 2.3.0
@angular/http نسخه 2.3.0
@angular/router نسخه 3.3.0
بسته روتر قبلاً نسخه 3 است، بنابراین برای جلوگیری از سردرگمی به نسخه Angular 4 و نسخه 3 نادیده گرفته شده است.
اندازه فایل کد تولید شده توسط کامپایلر در حالت AOT بسیار کاهش یافته است.
با Angular 4 اندازه بستههای تولیدی صدها کیلوبایت کاهش مییابد.
ویژگی های انیمیشن از angular/core حذف شده و به عنوان یک بسته جداگانه تشکیل میشه.
پشتیبانی از Typescript 2.1 و 2.2.
جهانی انگولاری
HttpClient جدید
Angular 5 انگولاری را سریعتر میکنه. زمان بارگذاری و زمان اجرا را بهبود بخشید.
با بهینه ساز ساخت جدید ارسال میشه.
پشتیبانی از Typescript 2.5.
service worker
در ماه می 2018 منتشر شد.
شامل رابط خط فرمان انگولاری (CLI)، کیت توسعه اجزا (CDK)، بسته مواد انگولاری، عناصر انگولاری.
رفع اشکال service worker.
i18n
حالت آزمایشی برای آیوی.
RxJS 6.0
tree shaking
در اکتبر 2018 منتشر شد.
TypeScript 3.1
RxJS 6.3
Angular CLI جدید
قابلیت CLI Prompts توانایی پرسیدن سوالات از کاربر را قبل از اجرا فراهم میکنه. مانند گفتگوی تعاملی بین کاربر و CLI است
با بهبود قابلیت CLI Prompts، به توسعه دهندگان کمک میکنه تا تصمیم بگیرند. دستورات جدید ng از کاربران میخواهند مسیریابی و انواع سبکهای CSS (SCSS) و ng add @angular/material تم و ژستها یا انیمیشنها را میخواهد.
در ماه می 2019 منتشر شد.
TypeScript 3.4
در فوریه 2020 منتشر شد.
TypeScript 3.7
Ivy به طور پیش فرض فعال است
در ژوئن 2020 منتشر شد.
TypeScript 3.9
TSlib 2.0
در زیر لیستی از اصول امنیتی در انگولاری آورده شده است.
باید از استفاده مستقیم از APIهای DOM اجتناب کنید.
شما باید Content Security Policy (CSP) را فعال کرده و وب سرور خود را برای بازگرداندن هدرهای مناسب CSP HTTP پیکربندی کنید.
باید از کامپایلر قالب آفلاین استفاده کنید.
باید از محافظ XSS سمت سرور استفاده کنید.
باید از DOM Sanitizer استفاده کنید.
شما باید از حملات CSRF یا XSRF جلوگیری کنید.
Angular از ادغام با Web Tracing Framework (WTF) به منظور اجرای عملیات پشتیبانی شده است. از آنجایی که به خوبی نگهداری نمیشه و در اکثر برنامه ها شکسته میشه، در آخرین نسخه منسوخ شده است.
هر دو «@angular/platform-webworker» و «@angular/platform-webworker-dynamic» رسماً منسوخ شدهاند، تیم Angular متوجه شد که اجرای برنامه Angular روی Web worker عمل خوبی نیست.
Angular CLI نسخه نصب شده خود را با استفاده از روش های مختلف زیر با استفاده از دستور ng ارائه می دهد
ng v
ng version
ng -v
ng --version
و خروجی به صورت زیر خواهد بود:
Angular CLI: 1.6.3 Node: 8.11.3 OS: darwin x64 Angular: ...
Angular از جدیدترین مرورگرها پشتیبانی میکنه که شامل مرورگرهای دسکتاپ و موبایل میشه.
مرورگر | نسخه |
---|---|
کروم | آخرین |
فایرفاکس | آخرین |
لبه | 2 جدیدترین نسخه اصلی |
IE | 11، 10، 9 (حالت سازگاری پشتیبانی نمیشه) |
سافاری | 2 جدیدترین نسخه اصلی |
اینترنت اکسپلورر موبایل | 11 |
iOS | 2 جدیدترین نسخه اصلی |
اندروید | 7.0، 6.0، 5.0، 5.1، 4.4 |
این یک کتابخونه داربستی است که نحوه تولید یا تبدیل یک پروژه برنامه نویسی را با ایجاد، اصلاح، تغییر شکل یا جابجایی فایل ها و کد تعریف میکنه. قوانینی را تعریف میکنه که بر روی یک فایل سیستم مجازی به نام درخت عمل می کنند.
در دنیای شماتیک، این تابعی است که روی درخت فایل برای ایجاد، حذف یا اصلاح فایلها به شیوهای خاص عمل میکند.
طرحواره ها با ابزار خط فرمان خود به نام Schematics CLI عرضه میشن. برای نصب شماتیک های اجرایی استفاده میشه که می تونین از آن برای ایجاد یک مجموعه شماتیک جدید با نام اولیه شماتیک استفاده کنید. پوشه مجموعه یک فضای کاری برای شماتیک ها است. همچنین می تونین از دستور schematics برای اضافه کردن یک شماتیک جدید به مجموعه موجود یا گسترش یک شماتیک موجود استفاده کنید. شما می تونین Schematic CLI را بصورت سراسری به صورت زیر نصب کنید.
npm install -g @angular-devkit/schematics-cli
در زیر بهترین شیوه های امنیتی در انگولاری آورده شده است.
از آخرین نسخه های کتابخونه Angular استفاده کنید
کپی Angular خود را تغییر ندهید
از API های Angular که در مستندات به عنوان "ریسک امنیتی" علامت گذاری شده اند، خودداری کنید.
Angular به طور پیش فرض همه مقادیر را غیرقابل اعتماد می داند. برای مثال، Angular پاکسازی میکند و از مقادیر نامعتبر فرار میکند وقتی یک مقدار از یک الگو، از طریق ویژگی، ویژگی، سبک، کلاس اتصال یا درونیابی در DOM درج میشه.
کامپایلر قالب آفلاین از آسیب پذیری های ناشی از تزریق قالب جلوگیری میکنه و عملکرد برنامه را تا حد زیادی بهبود می بخشد. بنابراین توصیه میشه از کامپایلر قالب آفلاین در استقرار تولید بدون ایجاد پویا هیچ قالبی استفاده کنید.
Angular زمینه های امنیتی زیر را برای پاکسازی تعریف میکنه:
HTML: هنگام تفسیر یک مقدار به عنوان HTML مانند اتصال به innerHtml استفاده میشه.
Style: هنگام اتصال CSS به ویژگی style استفاده میشه.
URL: برای ویژگی های URL مانند <a href>
استفاده میشه.
Resource URL: این یک URL است که به عنوان کدی مانند <script src>
بارگیری و اجرا میشه.
Sanitization بازرسی یک مقدار نامعتبر است که آن را به مقداری تبدیل میکنه که برای درج آن در DOM ایمن است. بله، Angular از ضد عفونی کردن پشتیبانی میکنه. مقادیر نامعتبر را برای HTML، سبکها و URLها پاکسازی میکند، اما پاکسازی URLهای منبع ممکن نیست چون حاوی کد دلخواه هستند.
innerHtml یکی از ویژگی های HTML-Elements است که به شما امکان می دهد محتوای html آن را به صورت برنامه ریزی شده تنظیم کنید. بیایید قطعه کد html زیر را در تگ «
<div [innerHTML]="htmlSnippet"></div>
و ویژگی htmlSnippet را از هر جزء تعریف کنید
export class myComponent { htmlSnippet: string = '<b>Hello World</b>, Angular'; }
متأسفانه این ویژگی می تونه باعث ایجاد اشکالات امنیتی Cross Site Scripting (XSS) در صورت مدیریت نادرست شود.
تفاوت اصلی بین کد درون یابی شده و کد داخلی در رفتار کد تفسیر شده است. محتوای درونیابی همیشه حذف میشه، یعنی HTML تفسیر نمیشه و مرورگر براکتهای انگولار را در محتوای متن عنصر نمایش میدهد. در جایی که در innerHTML binding، محتوا تفسیر میشه، یعنی مرورگر کاراکترهای < و > را به عنوان HTMLEntities تبدیل میکنه. برای مثال، استفاده در قالب به صورت زیر خواهد بود.
<p>Interpolated value:</p> <div >{{htmlSnippet}}</div> <p>Binding of innerHTML:</p> <div [innerHTML]="htmlSnippet"></div>
and the property defined in a component.
export class InnerHtmlBindingComponent { htmlSnippet = 'Template <script>alert("XSS Attack")</script> <b>Code attached</b>'; }
حتی با وجود اینکه innerHTML binding شانس حمله XSS را ایجاد میکنه، Angular این مقدار را ناامن تشخیص می دهد و به طور خودکار آن را پاکسازی میکنه.
گاهی اوقات برنامه ها واقعاً نیاز دارند که کدهای اجرایی مانند نمایش <iframe>
را از یک URL داشته باشند. در این مورد، باید با گفتن اینکه یک مقدار را بررسی کرده اید، نحوه تولید آن را بررسی کرده اید و مطمئن شده اید که همیشه ایمن است، از پاکسازی خودکار در Angular جلوگیری کنید. اساساً شامل 2 مرحله است،
Inject DomSanitizer: می تونین DomSanitizer را در کامپوننت به عنوان پارامتر در سازنده تزریق کنید.
با فراخوانی برخی از روشهای زیر، مقدار قابل اعتماد را علامتگذاری کنید
bypassSecurityTrustHtml
bypassSecurityTrustScript
bypassSecurityTrustStyle
bypassSecurityTrustUrl
bypassSecurityTrustResourceUrl
برای مثال، استفاده از url خطرناک به آدرس اینترنتی مورد اعتماد به صورت زیر خواهد بود.
constructor(private sanitizer: DomSanitizer) { this.dangerousUrl = 'javascript:alert("XSS attack")'; this.trustedUrl = sanitizer.bypassSecurityTrustUrl(this.dangerousUrl);
خیر، APIها یا روشهای داخلی مرورگر DOM بهطور خودکار از شما در برابر آسیبپذیریهای امنیتی محافظت نمیکنند. در این مورد توصیه میشه به جای تعامل مستقیم با DOM از قالب های Angular استفاده کنید. اگر اجتناب ناپذیر است، از عملکردهای ضدعفونی داخلی Angular استفاده کنید.
«DomSanitizer» برای کمک به جلوگیری از اشکالات امنیتی Cross Site Scripting (XSS) با پاکسازی مقادیر برای ایمن بودن استفاده در زمینههای مختلف DOM استفاده میشه.
حفاظت XSS سمت سرور در یک برنامه انگولاری با استفاده از زبان قالبی که به طور خودکار از مقادیر برای جلوگیری از آسیب پذیری های XSS در سرور فرار میکنه، پشتیبانی میشه. اما از زبان قالب برای تولید الگوهای Angular در سمت سرور استفاده نکنید که خطر زیادی برای معرفی آسیبپذیریهای تزریق قالب ایجاد میکند.
Angular دارای پشتیبانی داخلی برای جلوگیری از آسیبپذیریهای سطح http مانند جعل درخواست بین سایتی (CSRF یا XSRF) و گنجاندن اسکریپت بین سایتی (XSSI) است. حتی اگر این آسیبپذیریها باید در سمت سرور کاهش یابند، Angular کمکهایی را برای آسانتر کردن ادغام در سمت کلاینت ارائه میکند.
HttpClient از مکانیزم نشانه ای پشتیبانی میکنه که برای جلوگیری از حملات XSRF استفاده میشه
کتابخونه HttpClient قرارداد پاسخهای JSON پیشوندی را تشخیص میدهد (که js غیرقابل اجرا با نویسههای ")]}'،\n" کد میکند) و به طور خودکار رشته ")]}'،\n" را از همه پاسخهای قبل حذف میکند. تجزیه بیشتر
رهگیرهای Http بخشی از @angular/common/http هستند که درخواستهای HTTP را از برنامه شما به سرور و برعکس در پاسخهای HTTP بررسی و تبدیل میکنند. این رهگیرها می تونن انواع مختلفی از وظایف ضمنی، از احراز هویت گرفته تا ثبت را انجام دهند.
نحو رابط HttpInterceptor مانند زیر است.
interface HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>
}
شما می تونین با اعلان یک کلاس سرویس که متد intercept() رابط HttpInterceptor را پیاده سازی میکنه، از interceptors استفاده کنید.
@Injectable() export class MyInterceptor implements HttpInterceptor { constructor() {} intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { ... } }
پس از آن می تونین از آن در ماژول خود استفاده کنید،
@NgModule({ ... providers: [ { provide: HTTP_INTERCEPTORS, useClass: MyInterceptor, multi: true } ] ... }) export class AppModule {}
رهگیرهای HTTP را می توان برای انواع مختلفی از وظایف استفاده کرد،
Authentication
Logging
Caching
Fake backend
URL transformation
Modifying headers
بله، Angular از چندین رهگیر در یک زمان پشتیبانی میکنه. می تونین چندین رهگیر را در ویژگی ارائه دهندگان تعریف کنید:
providers: [ { provide: HTTP_INTERCEPTORS, useClass: MyFirstInterceptor, multi: true }, { provide: HTTP_INTERCEPTORS, useClass: MySecondInterceptor, multi: true } ],
رهگیرها به ترتیبی که ارائه شده اند فراخوانی میشن. i.n، MyFirst Interceptor ابتدا در پیکربندی رهگیرهای بالا فراخوانی میشه.
میتوانید با وارد کردن «HttpClientModule» فقط در AppModule خود، از همان نمونه «HttpInterceptors» برای کل برنامه استفاده کنید، و رهگیرها را به انژکتور برنامه root اضافه کنید.
برای مثال، بیایید کلاسی را تعریف کنیم که در برنامه root قابل تزریق باشد.
@Injectable() export class MyInterceptor implements HttpInterceptor { intercept( req: HttpRequest<any>, next: HttpHandler ): Observable<HttpEvent<any>> { return next.handle(req).do(event => { if (eventt instanceof HttpResponse) { // Code goes here } }); } }
پس از آن، HttpClientModule را در AppModule وارد کنید <span dir="ltr" align="left"> ```js @NgModule({ declarations: [AppComponent], imports: [BrowserModule, HttpClientModule], providers: [ { provide: HTTP_INTERCEPTORS, useClass: MyInterceptor, multi: true } ], bootstrap: [AppComponent] }) export class AppModule {} ``` </span> **[فهرست](#فهرست)**
Angular زمینه های بین المللی سازی زیر را ساده میکنه:
نمایش تاریخ، عدد، درصد و ارز در قالب محلی.
آماده سازی متن در قالب های مؤلفه برای ترجمه.
رسیدگی به اشکال جمع کلمات.
مدیریت متن جایگزین.
بهطور پیشفرض، Angular فقط حاوی دادههای محلی برای en-US است که انگلیسی است که در ایالات متحده آمریکا صحبت میشه. اما اگر میخواهید روی محلی دیگر تنظیم کنید، باید دادههای محلی را برای آن محلی جدید وارد کنین. پس از آن می تونین با استفاده از روش «registerLocaleData» ثبت نام کنین و نحو این روش به شکل زیر است.
registerLocaleData(data: any, localeId?: any, extraData?: any): void
برای مثال، اجازه دهید ما زبان آلمانی را وارد کنیم و آن را در برنامه ثبت کنیم
import { registerLocaleData } from '@angular/common'; import localeDe from '@angular/common/locales/de'; registerLocaleData(localeDe, 'de');
فرآیند ترجمه قالب i18n دارای چهار مرحله است:
Mark static text messages in your component templates for translation: می تونین i18n را روی هر تگ عنصری که متن ثابت آن باید ترجمه شود قرار دهید. برای مثال، برای عنوان زیر به ویژگی i18n نیاز دارید.
<h1 i18n>Hello i18n!</h1>
Create a translation file: از دستور Angular CLI xi18n برای استخراج متن علامت گذاری شده در یک فایل منبع ترجمه استاندارد صنعتی استفاده کنین. برای مثال، پنجره ترمینال را در ریشه پروژه برنامه باز کنین و دستور CLI xi18n را اجرا کنین.
```bash ng xi18n ```
دستور بالا فایلی به نام «messages.xlf» در دایرکتوری ریشه پروژه شما ایجاد میکنه.
Note: می تونین گزینه های دستوری را برای تغییر قالب، نام، مکان و محل منبع فایل استخراج شده ارائه کنین.
<trans-unit id="greetingHeader" datatype="html"> <source>Hello i18n!</source> <target>Hallo i18n !</target> <note priority="1" from="description">A welcome header for this sample</note> <note priority="1" from="meaning">welcome message</note> </trans-unit>
Merge the completed translation file into the app: شما باید از دستور ساخت Angular CLI برای کامپایل برنامه، انتخاب یک پیکربندی خاص محلی، یا مشخص کردن گزینه های دستور زیر استفاده کنین.
--i18nFile=path to the translation file
--i18nFormat=format of the translation file
--i18nLocale= locale id
ویژگی Angular i18n محتوای قابل ترجمه را علامت گذاری میکنه. این یک ویژگی سفارشی است که توسط ابزارها و کامپایلرهای Angular شناسایی میشه. کامپایلر پس از ترجمه آن را حذف میکنه.
Note: به یاد داشته باشید که i18n یک دستورالعمل Angular نیست.
هنگامی که متن قابل ترجمه را تغییر میدهید، ابزار استخراج Angular یک شناسه جدید برای آن واحد ترجمه ایجاد میکند. به دلیل این رفتار، باید هر بار فایل ترجمه را با شناسه جدید به روز کنید.
برای مثال، فایل ترجمه «messages.de.xlf.html» برای برخی از پیامهای متنی زیر واحد انتقال ایجاد کرده است:
<trans-unit id="827wwe104d3d69bf669f823jjde888" datatype="html">
میتوانید با تعیین یک شناسه سفارشی در ویژگی i18n با استفاده از پیشوند @@ از این بهروزرسانی دستی ویژگی «id» اجتناب کنید.
<h1 i18n="@@welcomeHeader">Hello i18n!</h1>
شما باید شناسه های سفارشی را منحصر به فرد تعریف کنید. اگر از یک شناسه برای دو پیام متنی مختلف استفاده می کنید، فقط اولین مورد استخراج میشه. اما ترجمه آن به جای هر دو پیامک اصلی استفاده میشه.
برای مثال، بیایید همان شناسه سفارشی myCustomId را برای دو پیام تعریف کنیم:
<h2 i18n="@@myCustomId">Good morning</h3> <!-- ... --> <h2 i18n="@@myCustomId">Good night</p>
و واحد ترجمه برای اولین متن در زبان آلمانی به عنوان
<trans-unit id="myId" datatype="html"> <source>Good morning</source> <target state="new">Guten Morgen</target> </trans-unit>
از آنجایی که شناسه سفارشی یکسان است، هر دو عنصر در ترجمه حاوی متنی مشابه زیر هستند
<h2>Guten Morgen</h2> <h2>Guten Morgen</h2>
بله، میتوانید با استفاده از ویژگی «
<ng-container i18n>I'm not using any DOM element for translation</ng-container>
به یاد داشته باشید که «
میتوانید ویژگیها را با پیوست کردن ویژگی «i18n-x» ترجمه کنین، جایی که x نام ویژگی برای ترجمه است. برای مثال، می تونین ویژگی عنوان تصویر را به صورت زیر ترجمه کنین.
<img [src]="example" i18n-title title="Internationlization" />
به هر حال، شما همچنین می تونین معنی، توضیحات و شناسه را با نحو i18n-x="<meaning>|<description>@@<id>" اختصاص دهید. **[فهرست](#فهرست)**
تعدد بسته به زبان دارای دسته های زیر است.
= 0 (یا هر عدد دیگری)
صفر
یک
دو
تعداد کمی
بسیاری
دیگر
عبارت ICU شبیه عبارات جمع است با این تفاوت که شما از بین ترجمه های جایگزین بر اساس مقدار رشته به جای عدد انتخاب می کنین. در اینجا شما آن مقادیر رشته را تعریف می کنین.
بیایید مؤلفه را با ویژگی «residenceStatus» که دارای مقادیر ممکن «شهروند»، «مقیم دائم» و «خارجی» است، در نظر بگیریم و پیام آن مقادیر را به ترجمههای مناسب نگاشت میکند.
<span i18n>The person is {residenceStatus, select, citizen {citizen} permanent resident {permanentResident} foreigner {foreigner}}</span>
بهطور پیشفرض، هنگامی که ترجمه وجود ندارد، پیام هشداری مانند «ترجمه از دست رفته برای پیام «somekey» ایجاد میکند. اما می تونین با سطح متفاوتی از پیام در کامپایلر Angular به صورت زیر پیکربندی کنین.
Error: خطا میده اگر از کامپایل AOT استفاده می کنین، بیلد با شکست مواجه میشه. اما اگر از کامپایل JIT استفاده می کنین، برنامه بارگذاری نمیشه.
Warning (default): این یک اخطار «مفقود ترجمه» را در کنسول یا پوسته نشان میدهد.
Ignore: هیچ کاری نمیکنه.
اگر از کامپایلر AOT استفاده می کنین، باید تغییراتی را در بخش پیکربندی فایل پیکربندی Angular CLI خود، angular.json انجام دهید.
"configurations": { ... "de": { ... "i18nMissingTranslation": "error" } }
اگر از کامپایلر JIT استفاده می کنین، سطح هشدار را در پیکربندی کامپایلر در بوت استرپ با افزودن ویژگی MissingTranslationStrategy به صورت زیر مشخص کنین:
import { MissingTranslationStrategy } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app/app.module'; platformBrowserDynamic().bootstrapModule(AppModule, { missingTranslation: MissingTranslationStrategy.Error, providers: [ // ... ] });
میتوانید پیکربندی ساخت مانند مسیر فایل ترجمه، نام، قالب و آدرس برنامه را در تنظیمات «پیکربندی» فایل Angular.json ارائه کنین. برای مثال، نسخه آلمانی برنامه شما بیلد را به صورت زیر پیکربندی کرده است:
"configurations": {
"de": {
"aot": true,
"outputPath": "dist/my-project-de/",
"baseHref": "/fr/",
"i18nFile": "src/locale/messages.de.xlf",
"i18nFormat": "xlf",
"i18nLocale": "de",
"i18nMissingTranslation": "error",
}
}
کتابخونه Angular یک پروژه Angular است که با یک برنامه تفاوت دارد چون نمی تونه به تنهایی اجرا شود. باید وارد شده و در یک برنامه استفاده شود. برای مثال، میتوانید کتابخونه «سرویسکار» را به یک برنامه Angular وارد یا اضافه کنین که یک برنامه کاربردی را به یک برنامه وب پیشرو (PWA) تبدیل میکند.
Note: شما می تونین کتابخونه شخص ثالث خود را ایجاد کنین و آن را به عنوان بسته npm منتشر کنین تا در یک برنامه استفاده شود.
کامپایلر AOT بخشی از یک فرآیند ساخت است که یک بسته برنامه کوچک، سریع و آماده برای اجرا تولید میکند، معمولاً برای تولید. این کد Angular HTML و TypeScript شما را در مرحله ساخت قبل از دانلود و اجرای آن کد به کد جاوا اسکریپت کارآمد تبدیل میکنه.
شما می تونین هر عنصر DOM را از طریق ElementRef با تزریق آن به سازنده کامپوننت خود کنترل کنین. یعنی کامپوننت باید سازنده ای با پارامتر ElementRef داشته باشد،
constructor(myElement: ElementRef) {
el.nativeElement.style.backgroundColor = 'yellow';
}
TestBed یک api برای نوشتن تست های واحد برای برنامه های Angular و کتابخونه های آن است. حتی با وجود اینکه ما هنوز تستهای خود را در Jasmine مینویسیم و با استفاده از Karma اجرا میکنیم، این API راه آسانتری برای ایجاد اجزا، مدیریت تزریق، آزمایش رفتار ناهمزمان و تعامل با برنامه ما ارائه میکند.
نقاله یک چارچوب تست سرتاسر برای برنامه های Angular و AngularJS است. این برنامه آزمایش هایی را بر روی برنامه شما که در یک مرورگر واقعی اجرا میشه، اجرا میکنه و مانند یک کاربر با آن تعامل دارد.
npm install -g protractor
مجموعه مجموعه ای از شماتیک های مرتبط است که در یک بسته npm جمع آوری شده است. برای مثال، مجموعه @schematics/angular
در Angular CLI برای اعمال تبدیل به یک پروژه برنامه وب استفاده میشه. شما می تونین مجموعه شماتیک خود را برای سفارشی سازی پروژه های انگولاری ایجاد کنین.
شما می تونین مجموعه های شماتیک خود را برای ادغام کتابخونه خود با Angular CLI ایجاد کنین. این مجموعه ها به عنوان 3 شماتیک اصلی طبقه بندی میشن.
می تونین با استفاده از 3 مرحله ساده از jquery در Angular استفاده کنین.
Install the dependency: ابتدا وابستگی jquery را با استفاده از npm نصب کنین
npm install --save jquery
Add the jquery script: در پروژه Angular-CLI، مسیر نسبی را به jquery در فایل angular.json اضافه کنین.
"scripts": [
"node_modules/jquery/dist/jquery.min.js"
]
Start using jquery: عنصر را در قالب تعریف کنین. در حالی که متغیر jquery را اعلام کرده و کلاس های CSS را روی عنصر اعمال کنین.
<div id="elementId"> <h1>JQuery integration</h1> </div>
import {Component, OnInit} from '@angular/core';
declare var $: any; // (or) import * as $ from 'jquery';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
ngOnInit(): void {
$(document).ready(() => {
$('#elementId').css({'text-color': 'blue', 'font-size': '150%'});
});
}
}
این استثنا به دلیل عدم وجود HttpClientModule در ماژول شما است. شما فقط باید در ماژول به صورت زیر وارد کنین:
import { HttpClientModule } from '@angular/common/http';
@NgModule({
imports: [
BrowserModule,
HttpClientModule,
],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
RouteState یک رابط است که وضعیت روتر را به عنوان درختی از مسیرهای فعال نشان می دهد.
interface RouterState extends Tree {
snapshot: RouterStateSnapshot
toString(): string
}
با استفاده از سرویس Router و ویژگی routerState می تونین از هر نقطه در برنامه Angular به RouterState فعلی دسترسی داشته باشید.
هنگامی که پروژه خود را با cli انگولاری ایجاد می کنین، می تونین از دستور "ng new" استفاده کنین. تمام اجزای شما را با فایل های sass از پیش تعریف شده تولید میکنه.
ng new My_New_Project --style=sass
اما اگر سبک موجود خود را در پروژه خود تغییر می دهید، از دستور ng set استفاده کنین.
ng set defaults.styleExt scss
ویژگی hidden برای نشان دادن یا پنهان کردن عنصر DOM مرتبط بر اساس یک عبارت استفاده میشه. می توان آن را نزدیک به دستورالعمل «ng-show» در AngularJS مقایسه کرد. فرض کنین می خواهید نام کاربری را بر اساس در دسترس بودن کاربر با استفاده از ویژگی "مخفی" نشان دهید.
<div [hidden]="!user.name">
My name is: {{user.name}}
</div>
تفاوت اصلی این است که *ngIf عنصر را از DOM حذف میکنه، در حالی که [hidden] در واقع با تنظیم «display:none» با سبک CSS بازی میکنه. به طور کلی اضافه کردن و حذف موارد از DOM برای اقدامات مکرر گران است.
لوله slice برای ایجاد یک آرایه یا رشته جدید حاوی زیرمجموعه (برش) از عناصر استفاده میشه. سینتکس به شکل زیر است:
{{ value_expression | slice : start [ : end ] }}
برای مثال، شما می تونین لیست "hello" را بر اساس یک آرایه تبریک ارائه کنین،
@Component({
selector: 'list-pipe',
template: `<ul>
<li *ngFor="let i of greeting | slice:0:5">{{i}}</li>
</ul>`
})
export class PipeListComponent {
greeting: string[] = ['h', 'e', 'l', 'l', 'o', 'm','o', 'r', 'n', 'i', 'n', 'g'];
}
ویژگی index دستورالعمل NgFor برای برگرداندن شاخص مبتنی بر صفر مورد در هر تکرار استفاده میشه. شما می تونین شاخص را در یک متغیر ورودی الگو گرفته و از آن در قالب استفاده کنین. برای مثال، میتوانید ایندکس را در متغیری به نام indexVar بگیرید و با استفاده از دستور ngFor به صورت زیر آن را با نام todo نمایش دهید. <span dir="ltr" align="left"> ```cmd <div *ngFor="let todo of todos; let i=index">{{i + 1}} - {{todo.name}}</div> ``` </span> **[فهرست](#فهرست)**
هدف اصلی استفاده از *ngFor with trackBy بهینه سازی عملکرد است. معمولاً اگر از NgFor با مجموعه دادههای بزرگ استفاده میکنین، یک تغییر کوچک به یک آیتم با حذف یا اضافه کردن یک مورد، میتونه باعث ایجاد آبشاری از دستکاریهای DOM شود. در این مورد، Angular فقط یک لیست تازه از ارجاعات اشیاء جدید و جایگزینی عناصر DOM قدیمی با تمام عناصر DOM جدید را می بیند. میتوانید با ارائه یک تابع «trackBy» که فهرست و مورد فعلی را بهعنوان آرگومان میگیرد و باید شناسه منحصربهفرد این مورد را برگرداند، به Angular کمک کنین تا موارد اضافه یا حذف شده را ردیابی کنه.
For example, lets set trackBy to the trackByTodos() method
<div *ngFor="let todo of todos; trackBy: trackByTodos">
({{todo.id}}) {{todo.name}}
</div>
and define the trackByTodos method,
trackByTodos(index: number, item: Todo): number { return todo.id; }
دستورالعمل NgSwitch شبیه دستور سوئیچ جاوا اسکریپت است که یک عنصر را از بین چندین عنصر ممکن بر اساس یک شرط سوئیچ نمایش می دهد. در این حالت فقط عنصر انتخاب شده در DOM قرار می گیرد. همراه با دستورات «NgSwitch»، «NgSwitchCase» و «NgSwitchDefault» استفاده شده است.
برای مثال، اجازه دهید جزئیات مرورگر را بر اساس مرورگر انتخابی با استفاده از دستورالعمل ngSwitch نمایش دهیم.
<div [ngSwitch]="currentBrowser.name">
<chrome-browser *ngSwitchCase="'chrome'" [item]="currentBrowser"></chrome-browser>
<firefox-browser *ngSwitchCase="'firefox'" [item]="currentBrowser"></firefox-browser>
<opera-browser *ngSwitchCase="'opera'" [item]="currentBrowser"></opera-browser>
<safari-browser *ngSwitchCase="'safari'" [item]="currentBrowser"></safari-browser>
<ie-browser *ngSwitchDefault [item]="currentItem"></ie-browser>
</div>
بله، به دو صورت می توان برای ورودی ها و خروجی ها نام مستعار انجام داد.
نام مستعار در ابرداده: ورودی ها و خروجی ها در فراداده با استفاده از یک رشته (😃 با نقطه مشخص (😃 با نام ویژگی دستوری در سمت چپ و نام مستعار عمومی در سمت راست نام مستعار میشن. یعنی در قالب ویژگی Name:alias خواهد بود.
inputs: ['input1: buyItem'],
outputs: ['outputEvent1: completedEvent']
Aliasing with @Input()/@Output() decorator: نام مستعار را می توان با ارسال نام مستعار به @Input()/@Output() decorator.i.e برای نام دارایی مشخص کرد. به شکل @Input(نام مستعار) یا @Output(نام مستعار) خواهد بود.
@Input('buyItem') input1: string;
@Output('completedEvent') outputEvent1 = new EventEmitter<string>();
اپراتور navigation ایمن (؟) (یا به عنوان اپراتور الویس شناخته میشه) برای محافظت در برابر مقادیر null و undefined در مسیرهای ویژگی استفاده میشه، زمانی که شما از وجود یا عدم وجود یک مسیر اطلاع ندارید. یعنی مقدار مسیر شی را در صورت وجود برمی گرداند، در غیر این صورت مقدار null را برمی گرداند.
For example, you can access nested properties of a user profile easily without null reference errors as below,
<p>The user firstName is: {{user?.fullName.firstName}}</p>
Using this safe navigation operator, Angular framework stops evaluating the expression when it hits the first null value and renders the view without any errors.
شما به پیکربندی خاصی نیاز ندارید. در Angular9، رندر Ivy کامپایلر پیش فرض Angular است. اگرچه Ivy خود Angular8 در دسترس است، باید آن را در فایل tsconfig.json به صورت زیر پیکربندی کنین:
"angularCompilerOptions": { "enableIvy": true }
Angular 9 با جایگزینی تابع get قدیمی با روش inject جدید، تغییرات ایمن نوع را در تغییرات TestBed API ارائه میکند. چون روش TestBed.get از نظر نوع ایمن نیست. استفاده به شرح زیر خواهد بود،
TestBed.get(ChangeDetectorRef) // returns any. It is deprecated now.
TestBed.inject(ChangeDetectorRef) // returns ChangeDetectorRef
در Angular 8، پرچم استاتیک برای ViewChild مورد نیاز است. در حالی که در Angular9، دیگر نیازی به عبور از این ویژگی ندارید. هنگامی که با استفاده از «ng update» به Angular9 بهروزرسانی کردید، انتقال اسکریپت { static: false } را در همه جا حذف میکند.
@ViewChild(ChildDirective) child: ChildDirective; // Angular9 usage
@ViewChild(ChildDirective, { static: false }) child: ChildDirective; //Angular8 usage
زبان عبارت الگوی Angular از سه عملگر خاص قالب پشتیبانی میکنه.
اپراتور لوله
اپراتور ناوبری ایمن
عملگر ادعای غیر تهی
اپراتور لوله نسبت به اپراتور سه تایی (?😃 اولویت بیشتری دارد. برای مثال، عبارت «اول؟ دوم : سوم | چهارم به عنوان «اول؟ دوم : (سوم | چهارم)`.
مؤلفه ورودی هر مؤلفه ای است که Angular به طور ضروری بارگذاری میکنه (یعنی عدم ارجاع آن در قالب) بر اساس نوع. به دلیل این رفتار، کامپایلر Angular در طول کامپایل نمی تونه آنها را پیدا کنه. این مؤلفه ها به صورت پویا با «ComponentFactoryResolver» ایجاد میشن.
اساساً دو نوع اصلی از مؤلفه های ورودی وجود دارد که به شرح زیر است:
مؤلفه ریشه بوت استرپ
مؤلفه ای که در مسیر مشخص می کنین
کامپوننت بوت استرپ یک جزء ورودی است که Angular در طول فرآیند بوت استرپ یا زمان راه اندازی برنامه در DOM بارگذاری میکنه. به طور کلی، این مؤلفه بوت استرپ یا ریشه به عنوان «AppComponent» در ماژول ریشه شما با استفاده از ویژگی «bootstrap» به شرح زیر نامگذاری میشه.
@NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, FormsModule, HttpClientModule, AppRoutingModule ], providers: [], bootstrap: [AppComponent] // bootstrapped entry component need to be declared here })
میتوانید به جای استفاده از آرایه بوت استرپ در حاشیهنویسی «@NgModule» از هوک «ngDoBootstrap» برای راهاندازی دستی برنامه استفاده کنین. این قلاب بخشی از رابط «DoBootstap» است.
interface DoBootstrap { ngDoBootstrap(appRef: ApplicationRef): void }
ماژول باید رابط فوق را پیاده سازی کنه تا از هوک برای بوت استرپینگ استفاده کنه.
class AppModule implements DoBootstrap { ngDoBootstrap(appRef: ApplicationRef) { appRef.bootstrap(AppComponent); // bootstrapped entry component need to be passed } }
بله، کامپوننت بوت استرپ باید جزء ورودی باشد. این به این دلیل است که فرآیند بوت استرپ یک فرآیند ضروری است.
اجزای مورد اشاره در پیکربندی روتر به عنوان اجزای ورودی مسیریابی نامیده میشن. این جزء ورودی مسیریابی شده در تعریف مسیر به صورت زیر تعریف شده است:
const routes: Routes = [ { path: '', component: TodoListComponent // router entry component } ];
از آنجایی که تعریف روتر شما را ملزم میکنه که کامپوننت را در دو مکان (روتر و ورودی کامپوننت) اضافه کنین، این اجزا همیشه جزء ورودی هستند.
توجه: کامپایلرها به اندازه کافی هوشمند هستند که تعریف روتر را تشخیص دهند و به طور خودکار جزء روتر را به "entryComponents" اضافه کنند.
اغلب اوقات، برای تنظیم اجزای ورودی در آرایه ورودیComponents ngModule decorator نیازی به صراحت ندارین. چون angular کامپوننتها را هم از تعاریف @NgModule.bootstrap و هم مسیر را بهطور خودکار به اجزای ورودی اضافه میکنه.
نه. در نسخههای انگولار قبلی، آرایه ورودی Components از ngModule decorator استفاده می شه تا به کامپایلر بگه کدوم مؤلفهها ایجاد شده و بهصورت پویا در view درج میشن. در Angular9، این دیگر با Ivy مورد نیاز نیست.
نه فقط اجزای ورودی و اجزای قالب در بیلدهای تولید ظاهر میشن. اگر یک جزء جزء ورودی نباشه و تو یه الگو پیدا نشه tree shaking اونو دور می اندازه. به همین دلیل، مطمئن شین که فقط اجزای ورودی واقعی را برای کاهش اندازه بسته اضافه کنین.
کامپایلر Angular برای تبدیل کد برنامه به کد جاوا اسکریپت استفاده میشه. نشانگذاری الگو را میخواند، اون رو با کد کلاس مؤلفه مربوطه ترکیب می کنه و کارخانههای مؤلفه را منتشر می کنه که نمایش جاوا اسکریپت مؤلفه را همراه با عناصر فراداده @Component ایجاد می کنه.
ابرداده @NgModule
برای اینکه به کامپایلر Angular بگوید چه اجزایی برای این ماژول کامپایل شود و چگونه این ماژول را با ماژولهای دیگر پیوند دهد استفاده میشه.
کامپایلر Angular وقتی یه کامپوننت یا directive رو تو قالب پیدا میکنه که بتونه با انتخابگر اون کامپوننت یا directive تو اون الگو مطابقت داشته باشه. ولی اگه نام pipe در سینتکس pipe قالب HTML ظاهر شه یه pipe پیدا میکنه.
کتابخونه های اصلی انگولاری و کتابخونه های شخص ثالث به عنوان ngmodules در دسترس هستن.
کتابخونه های انگولاری مانند FormsModule ، HttpclientModule و Routermodule Ngmodules هستن.
خیلی از کتابخونه های شخص ثالث مانند طراحی مواد ، یونی و AngularFire2 Ngmodules هستن.
ماژول های ویژگی Ngmodules هستن که به منظور سازماندهی کد استفاده میشن. ماژول ویژگی را می توان با استفاده از دستور زیر در فهرست root با Angular CLI ایجاد کرد ،
ng generate module MyCustomFeature //
Angular CLI پوشه ای به نام "My-Custom-Feature" با پرونده ای در داخل "My-Custom-Feature.module.ts" با محتویات زیر ایجاد میکنه
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
@NgModule({
imports: [
CommonModule
],
declarations: []
})
export class MyCustomFeature { }
Note: پسوند "ماژول" نباید در این نام وجود داشته باشد چون CLI آن را ضمیمه میکنه.
در ماژول ویژگی CLI تولید شده ، دو بیانیه واردات JavaScript در بالای پرونده وجود دارد
NgModule: برای استفاده از دکوراتور `@ngmodule '
CommonModule: این دستورالعمل های متداول بسیاری مانند "ngif" و "ngfor" رو ارائه می دن.
در زیر تفاوت های اصلی بین Ngmodule انگولاری و ماژول JavaScript وجود دارد:
ngmodule | ماژول JavaScript |
---|---|
فقط کلاسهای قابل اعلام Ngmodule | هیچ کلاس محدودیتی وجود ندارد |
کلاسهای ماژول رو فقط در آرایه اعلامیه ها لیست کنید | میتونه تمام کلاسهای عضو را در یک پرونده غول پیکر تعریف کنه |
این فقط کلاسهای قابل اعلام را که متعلق به آن است صادر میکنه یا از ماژول های دیگر وارد میکنه | این می تونه هر کلاس رو صادر کنه |
با افزودن ارائه دهندگان به ارائه آرایه | کل برنامه را با خدمات گسترش دهید |
اگر از یک مؤلفه بدون declaration اون استفاده می کنین ، Angular یک پیام خطا برمی گردونه.
اگر سعی می کنین در بیش از یک ماژول همون کلاس رو اعلام کنین ، کامپایلر خطایی رو ارسال میکنه.
عنصر (مؤلفه ، دستورالعمل و لوله) را ایجاد کنید و اون رو از پرونده ای که در اون نوشتید صادر کنید
اون را به ماژول مناسب وارد کنید.
اون را در آرایه اعلامیه ngmodule اعلام کنید.
اگر "BrowserModule" را به یک ماژول ویژگی lazy loading وارد می کنین ، Angular خطایی را برمی گرداند که به شما می گوید در عوض از "CommonModule" استفاده کنید. از آنجا که ارائه دهندگان BrowserModule برای کل برنامه هستند ، بنابراین فقط باید در ماژول ریشه باشد ، نه در ماژول ویژگی. در حالی که ماژول های ویژگی فقط به دستورالعمل های مشترک در Commodule نیاز دارند.
در زیر پنج دسته ماژول های ویژگی ،
دامنه: یک تجربه کاربر اختصاص داده شده به یک دامنه برنامه خاص (برای مثال ، سفارش ، ثبت نام و غیره را قرار دهید)
مسیریابی: اینها ماژول های ویژگی دامنه هستند که اجزای برتر آنها اهداف مسیرهای ناوبری روتر هستند.
مسیریابی: پیکربندی مسیریابی را برای ماژول دیگر فراهم میکنه.
سرویس: این سرویس های نرم افزاری مانند دسترسی به داده ها و پیام رسانی را ارائه می دهد (برای مثال ، httpclientmodule)
ویجت: این مؤلفه ها ، دستورالعمل ها و لوله ها را در دسترس ماژول های خارجی قرار می دهد (برای مثال ، کتابخونه های شخص ثالث مانند UI مواد)
ارائه دهنده دستورالعمل سیستم تزریق وابستگی در مورد چگونگی به دست آوردن ارزش برای وابستگی (خدمات با نام مستعار ایجاد شده) است. این سرویس را می توان با استفاده از Angular CLI به شرح زیر ارائه داد:
ng generate service my-service
سرویس ایجاد شده توسط CLI به شرح زیر خواهد بود:
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root', //Angular provide the service in root injector }) export class MyService { }
شما همیشه باید خدمات خود را در انژکتور ریشه ارائه دهید مگر اینکه موردی وجود داشته باشد که بخواهید این سرویس فقط در صورت وارد کردن یک ngmodule خاص در دسترس باشد.
به جای آن می توان دامنه ارائه دهنده خدمات را به یک ماژول خاص محدود کرد و به جای آن در دسترس کل برنامه قرار گرفت. دو روش ممکن برای انجام آن وجود دارد.
Using providedIn in service:
import { Injectable } from '@angular/core'; import { SomeModule } from './some.module'; @Injectable({ providedIn: SomeModule, }) export class SomeService { }
Declare provider for the service in module:
import { NgModule } from '@angular/core'; import { SomeService } from './some.service'; @NgModule({ providers: [SomeService], }) export class SomeModule { }
دو روش ممکن برای ارائه یک سرویس مجرد وجود دارد.
ویژگی ارائه شده از injectable () را روی "ریشه" تنظیم کنید. این روش ارجح (شروع از Angular 6.0) از ایجاد یک سرویس Singleton است چون خدمات شما را لرزان میکنه.
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root', }) export class MyService { }
سرویس را در ماژول root یا در یک ماژول که فقط توسط ماژول ریشه وارد میشه ، وارد کنید. از آن برای ثبت خدمات قبل از Angular 6.0 استفاده شده است.
@NgModule({ // ... providers: [MyService], // ... })
اگر یک ماژول تعریف و اعلامیه ها را تعریف کند ، بارگیری ماژول در ماژول های چند ویژگی ، ثبت نام سرویس را کپی میکنه. در زیر روشهای مختلفی برای جلوگیری از این رفتار تکراری آورده شده است.
به جای ثبت سرویس در ماژول ، از نحو ارائه شده استفاده کنید.
خدمات خود را در ماژول خود جدا کنید.
روشهای Forroot () و Forchild () را در ماژول تعریف کنید.
اگر ماژول «Routermodule» روش استاتیک Forroot () ندارد ، هر ماژول ویژگی یک نمونه روتر جدید را فوری میکنه ، که به دلیل موارد تکراری منجر به کاربرد شکسته میشه. پس از استفاده از روش forroot () ، ماژول برنامه root routermodule.forroot (...)
را وارد میکنه و روتر میشه و همه ماژول های ویژگی واردات routermodule.forchild (...)
که روتر دیگری را فوری نمیکنه.
ماژول مشترک ماژولی است که در آن دستورالعمل ها ، لوله ها و اجزای متداول را در یک ماژول که به اشتراک گذاشته شده است (وارد می کنید) در طول برنامه قرار دهید.
برای مثال ، ماژول مشترک زیر واردات متداول ، formsmodule برای دستورالعمل های مشترک و مؤلفه ها ، لوله ها و دستورالعمل ها بر اساس نیاز ،
import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { UserComponent } from './user.component'; import { NewUserDirective } from './new-user.directive'; import { OrdersPipe } from './orders.pipe'; @NgModule({ imports: [ CommonModule ], declarations: [ UserComponent, NewUserDirective, OrdersPipe ], exports: [ UserComponent, NewUserDirective, OrdersPipe, CommonModule, FormsModule ] }) export class SharedModule { }
نه ، توصیه نمیشه با وارد کردن ماژول خدمات را به اشتراک بگذارید. یعنی ماژول ها را وارد کنید وقتی می خواهید فقط از دستورالعمل ها ، لوله ها و مؤلفه ها استفاده کنید. بهترین روش برای به دست آوردن خدمات مشترک از طریق "تزریق وابستگی انگولاری" است چون وارد کردن یک ماژول منجر به یک نمونه خدمات جدید خواهد شد.
در زاویه 9.1 ، می توان از روش API "getLocalEdirection" برای به دست آوردن جهت فعلی در برنامه خود استفاده کرد. این روش برای پشتیبانی از مناطق راست به چپ برای برنامه های مبتنی بر بین المللی شما مفید است.
import { getLocaleDirection, registerLocaleData } from '@angular/common'; import { LOCALE_ID } from '@angular/core'; import localeAr from '@angular/common/locales/ar'; // ... constructor(@Inject(LOCALE_ID) locale) { const directionForLocale = getLocaleDirection(locale); // Returns 'rtl' or 'ltr' based on the current locale registerLocaleData(localeAr, 'ar-ae'); const direction = getLocaleDirection('ar-ae'); // Returns 'rtl' // Current direction is used to provide conditional logic here }
NGCC (کامپایلر سازگاری انگولاری) ابزاری است که Node_Module را با NDEDULE با NDIV NGC به قالب سازگار با پیچک ساخته میکنه. اسکریپت postinstall
از pack.json مطمئن خواهد شد که node_modules شما با رندر پیچک سازگار خواهد بود.
"scripts": { "postinstall": "ngcc" }
Whereas, Ivy compiler (ngtsc), which compiles Ivy-compatible code.
کلاس که قبلاً در هر ماژول دیگری اعلام شده است.
دستورالعمل های وارد شده از یک ماژول دیگر.
کلاس های ماژول.
کلاسهای خدمات.
کلاس ها و اشیاء غیر حرکتی ، مانند رشته ها ، اعداد ، توابع ، مدل های موجودیت ، تنظیمات ، منطق تجارت و کلاس های یاور.
Angular خدماتی به نام NGZONE را ارائه می دهد که منطقه ای به نام "Angular" ایجاد میکنه تا در صورت رضایت از شرایط زیر ، به طور خودکار تشخیص تغییر را ایجاد کند.
هنگامی که یک عملکرد همگام سازی یا ASYNC اجرا میشه.
هنگامی که هیچ برنامه ریزی میکروتاسکی برنامه ریزی نشده است.
منطقه به طور پیش فرض در برنامه های انگولاری بارگیری و مورد نیاز است و به زاویه کمک میکنه تا بداند چه موقع باعث تشخیص تغییر میشه. به این ترتیب ، این باعث میشه که توسعه دهندگان Sures روی توسعه برنامه و نه اصلی ترین قسمت انگولاری متمرکز شوند. همچنین می تونین از Angular بدون منطقه استفاده کنید اما تشخیص تغییر باید به تنهایی اجرا شود و «Zone Zone» باید در فرآیند bootstrap پیکربندی شود. بیایید دو مرحله زیر را برای حذف Zone.js دنبال کنیم. 1. واردات Zone.js را از polyfills.ts حذف کنید. <span dir="ltr" align="left"> ```js /*************************************************************************************************** * Zone JS is required by default for Angular itself. */ // import 'zone.js/dist/zone'; // Included with Angular CLI. ``` </span> 2. Bootstrap Angular با منطقه NOOP در SRC/Main.ts. <span dir="ltr" align="left"> ```js platformBrowserDynamic().bootstrapModule(AppModule, {ngZone: 'noop'}) .catch(err => console.error(err)); ``` </span> **[فهرست](#فهرست)**
به طور پیش فرض ، Angular CLI مؤلفه هایی را در یک حالت نمایش داده شده درون خطی ایجاد میکنه (یعنی صفحه نمایش: درون خطی). اما ایجاد مؤلفه هایی با نمایشگر امکان پذیر است: سبک بلوک با استفاده از گزینه "DisplayBlock":
ng generate component my-component --displayBlock
(OR) the option can be turned on by default in Angular.json with schematics.@schematics/angular:component.displayBlock
key value as true.
حالت هایی که موقع حساسیت به تغییر میتونه ایجاد بشه چیا هستن؟etection?
تشخیص تغییر در سناریوهای زیر کار میکنه که در آن داده ها برای به روزرسانی برنامه HTML نیاز دارند.
اولیه سازی مؤلفه: در حالی که راه اندازی کاربرد انگولاری ، انگولاری باعث میشه ApplicationRef.tick ()
برای تماس با تشخیص تغییر و مشاهده.
شنونده رویداد: شنونده رویداد DOM می تونه داده ها را در یک مؤلفه انگولاری به روز کند و باعث تغییر در تغییر نیز شود.
@Component({ selector: 'app-event-listener', template: ` <button (click)="onClick()">Click</button> {{message}}` }) export class EventListenerComponent { message = ''; onClick() { this.message = 'data updated'; } }
HTTP Data Request: می تونین از طریق درخواست HTTP داده ها را از یک سرور دریافت کنید
data = 'default value'; constructor(private httpClient: HttpClient) {} ngOnInit() { this.httpClient.get(this.serverUrl).subscribe(response => { this.data = response.data; // change detection will happen automatically }); }
Macro tasks setTimeout() or setInterval(): می تونین داده ها را در عملکرد پاسخ به تماس SettimeOut یا SetInterval به روز کنید
data = 'default value'; ngOnInit() { setTimeout(() => { this.data = 'data updated'; // Change detection will happen automatically }); }
Micro tasks Promises: شما می تونین داده ها را در عملکرد پاسخ به قول وعده به روز کنید
data = 'initial value'; ngOnInit() { Promise.resolve(1).then(v => { this.data = v; // Change detection will happen automatically }); }
Async operations like Web sockets and Canvas: داده ها را می توان به صورت ناهمزمان با استفاده از websocket.onmessage () و canvas.toblob () به روز کرد.
زمینه اجرای یک مفهوم انتزاعی است که اطلاعات مربوط به محیط را در کد فعلی اجرا میکنه. یک منطقه زمینه اعدام را فراهم میکنه که در عملیات ناهمزمان ادامه می یابد ، به عنوان زمینه منطقه خوانده میشه. برای مثال ، زمینه منطقه در عملکرد برگشت به تماس در خارج و داخل SettimeOut یکسان خواهد بود ،
zone.run(() => { // outside zone expect(zoneThis).toBe(zone); setTimeout(function() { // the same outside zone exist here expect(zoneThis).toBe(zone); }); });
The current zone is retrieved through Zone.current
.
چهار قلاب چرخه عمر برای عملیات ناهمزمان از Zone.js. وجود دارد.
onScheduleTask: این قلاب هنگام برنامه ریزی یک کار ناهمزمان جدید ایجاد میشه. برای مثال ، وقتی با SetTimeOut تماس می گیرید ()
onScheduleTask: function(delegate, curr, target, task) { console.log('new task is scheduled:', task.type, task.source); return delegate.scheduleTask(target, task); }
onInvokeTask: این قلاب هنگامی که یک کار ناهمزمان در حال انجام است ، ایجاد میکنه. برای مثال ، هنگامی که پاسخ به تماس SettimeOut () در حال اجرا است.
onInvokeTask: function(delegate, curr, target, task, applyThis, applyArgs) { console.log('task will be invoked:', task.type, task.source); return delegate.invokeTask(target, task, applyThis, applyArgs); }
onHasTask: این قلاب هنگامی که وضعیت یک نوع کار در داخل یک منطقه از پایدار (بدون کار در منطقه) به ناپایدار تغییر میکنه (یک کار جدید در منطقه برنامه ریزی شده است) یا از ناپایدار تا پایدار تغییر میکنه.
onHasTask: function(delegate, curr, target, hasTaskState) { console.log('task state changed in the zone:', hasTaskState); return delegate.hasTask(target, hasTaskState); }
onInvoke: این قلاب هنگامی که یک عملکرد همزمان در منطقه اجرا میشه ، ایجاد میشه.
onInvoke: function(delegate, curr, target, callback, applyThis, applyArgs) { console.log('the callback will be invoked:', callback); return delegate.invoke(target, callback, applyThis, applyArgs); }
سرویس NGZONE یک روش `run () را ارائه می دهد که به شما امکان می دهد عملکردی را در داخل منطقه انگولاری اجرا کنید. این عملکرد برای اجرای API های شخص ثالث که توسط منطقه اداره نمیشن و باعث تشخیص تغییر خودکار در زمان صحیح میشن ، استفاده میشه.
export class AppComponent implements OnInit { constructor(private ngZone: NgZone) {} ngOnInit() { // use ngZone.run() to make the asynchronous operation in the angular zone this.ngZone.run(() => { someNewAsyncAPI(() => { // update the data of the component }); }); } }
در حالی که "روش runoutsideangular ()` استفاده میشه وقتی که نمی خواهید تغییر تغییر را ایجاد کنید.
export class AppComponent implements OnInit { constructor(private ngZone: NgZone) {} ngOnInit() { // Use this method when you know no data will be updated this.ngZone.runOutsideAngular(() => { setTimeout(() => { // update component data and don't trigger change detection }); }); } }
شما می تونین با پیکربندی آنها در یک پرونده جداگانه ، تنظیمات منطقه را تغییر داده و درست پس از واردات Zonejs وارد کنید.
برای مثال ، شما می تونین Patch Monkey RequestAnimationFrame () را غیرفعال کنید تا از تغییر برای به روزرسانی داده به عنوان یک تنظیم جلوگیری کنید و از وقایع DOM (یک رویداد Mousemove یا Scroll) جلوگیری کنید تا تغییر تغییر را ایجاد کند. بیایید بگوییم پرونده جدید به نام Zone-flags.js ،
// disable patching requestAnimationFrame (window as any).__Zone_disable_requestAnimationFrame = true; // disable patching specified eventNames (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove'];
پرونده پیکربندی فوق را می توان در یک پرونده polyfill.ts به شرح زیر وارد کرد:
/*************************************************************************************************** * Zone JS is required by default for Angular. */ import `./zone-flags`; import 'zone.js/dist/zone'; // Included with Angular CLI.
Angular یک عملکرد "ماشه ()" برای انیمیشن را به منظور جمع آوری حالت ها و انتقال با یک نام انیمیشن خاص فراهم میکنه تا بتوانید آن را به عنصر تحریک در الگوی HTML وصل کنید. این عملکرد را برای تغییرات تماشا میکنه و هنگام تغییر ، اقدامات را آغاز میکنه.
برای مثال ، بیایید Trigger به نام "Updown" ایجاد کنیم و آن را به عنصر دکمه وصل کنیم.
@Component({ selector: 'app-up-down', animations: [ trigger('upDown', [ state('up', style({ height: '200px', opacity: 1, backgroundColor: 'yellow' })), state('down', style({ height: '100px', opacity: 0.5, backgroundColor: 'green' })), transition('up => down', [ animate('1s') ]), transition('down => up', [ animate('0.5s') ]), ]), ], templateUrl: 'up-down.component.html', styleUrls: ['up-down.component.css'] }) export class UpDownComponent { isUp = true; toggle() { this.isUp = !this.isUp; } }
با تعیین مقدار ابرداده می تونین انژکتورها را با ارائه دهندگان در سطوح مختلف برنامه خود پیکربندی کنید. پیکربندی می تونه در یکی از سه مکان اتفاق بیفتد ،
In the @Injectable()
decorator for the service itself
In the @NgModule()
decorator for an NgModule
In the @Component()
decorator for a component
نه. اگر کلاس دارای دکوراتورهای انگولاری دیگری بر روی آن باشد یا هیچ وابستگی نداشته باشد ، دکوراتور injectable ()
`injectable () لازم نیست. اما نکته مهم در اینجا هر کلاس است که با زاویه تزریق میشه تزئین شده است.
یعنی اگر دکوراتور را اضافه کنیم ، ابرداده "طراحی: پارامترها" اضافه میشه ، و تزریق وابستگی می تونه کار خود را انجام دهد. این دلیل دقیق اضافه کردن دکوراتور injectable () در یک سرویس در صورتی است که این سرویس دارای برخی وابستگی ها باشد.
برای مثال ، بیایید تغییرات مختلف AppService را در یک جزء ریشه مشاهده کنیم ،
AppService زیر را می توان بدون هیچ مشکلی در AppComponent تزریق کرد. این امر به این دلیل است که هیچ سرویس وابستگی در AppService وجود ندارد.
export class AppService { constructor() { console.log('A new app service'); } }
AppService زیر با دکوراتور ساختگی و Httpservice میتونه بدون هیچ مشکلی در AppComponent تزریق شود. این امر به این دلیل است که اطلاعات متا با دکوراتور ساختگی تولید میشه.
function SomeDummyDecorator() { return (constructor: Function) => console.log(constructor); } @SomeDummyDecorator() export class AppService { constructor(http: HttpService) { console.log(http); } }
و کد JavaScript تولید شده از خدمات فوق دارای اطلاعات متا در مورد httpservice است ،
var AppService = (function () { function AppService(http) { console.log(http); } AppService = __decorate([ core_1.Injectable(), __metadata('design:paramtypes', [http_service_1.HttpService]) ], AppService); return AppService; }()); exports.AppService = AppService;
AppService زیر با تزئینات injectable و httpservice می تونه بدون هیچ مشکلی در AppComponent تزریق شود. این امر به این دلیل است که اطلاعات متا با تزئینات تزریقی تولید میشه.
@Injectable({ providedIn: 'root', }) export class AppService { constructor(http: HttpService) { console.log(http); } }
وابستگی اختیاری یک دکوراتور پارامتر است که در پارامترهای سازنده مورد استفاده قرار می گیرد ، که این پارامتر را به عنوان یک وابستگی اختیاری نشان می دهد. به همین دلیل ، در صورت عدم یافتن وابستگی ، چارچوب DI تهی را تهی میکنه.
برای مثال ، اگر شما یک ارائه دهنده logger را در هیچ کجا ثبت نکنید ، انژکتور مقدار logger (یا سرویس logger) را در کلاس زیر تنظیم میکنه.
import { Optional } from '@angular/core'; constructor(@Optional() private logger?: Logger) { if (this.logger) { this.logger.log('This is an optional dependency message'); } else { console.log('The logger is not registered'); } }
There are two types of injector hierarchies in Angular
ModuleInjector hierarchy: آن را با استفاده از حاشیه نویسی ngmodule () یا injectable () در سطح ماژول پیکربندی میکنه.
**ElementInjector hierarchy:**این به طور ضمنی در هر عنصر DOM ایجاد کرد. همچنین به طور پیش فرض خالی است ، مگر اینکه آن را در ویژگی ارائه دهندگان در Directive () یا component () پیکربندی کنید.
فرم های واکنشی یک رویکرد مدل محور برای ایجاد فرم ها به سبک واکنشی است (ورودی های فرم با گذشت زمان تغییر می کنند). اینها در اطراف جریانهای قابل مشاهده ساخته شده اند ، جایی که ورودی ها و مقادیر فرم به عنوان جریان مقادیر ورودی ارائه میشن. بیایید مراحل زیر را برای ایجاد فرم های واکنشی دنبال کنیم ،
ماژول فرم های واکنشی را ثبت کنید که دستورالعمل های واکنش پذیر را در برنامه شما اعلام میکنه
import { ReactiveFormsModule } from '@angular/forms'; @NgModule({ imports: [ // other imports ... ReactiveFormsModule ], }) export class AppModule { }
یک نمونه جدید FormControl ایجاد کنید و آن را در مؤلفه ذخیره کنید.
import { Component } from '@angular/core'; import { FormControl } from '@angular/forms'; @Component({ selector: 'user-profile', styleUrls: ['./user-profile.component.css'] }) export class UserProfileComponent { userName = new FormControl(''); }
FormControl را در الگوی ثبت کنید.
<label> User name: <input type="text" [formControl]="userName"> </label>
سرانجام ، مؤلفه با کنترل فرم واکنشی به شرح زیر ظاهر میشه:
import { Component } from '@angular/core'; import { FormControl } from '@angular/forms'; @Component({ selector: 'user-profile', styleUrls: ['./user-profile.component.css'] template: ` <label> User name: <input type="text" [formControl]="userName"> </label> ` }) export class UserProfileComponent { userName = new FormControl(''); }
فرم های پویا الگویی است که در آن ما یک فرم را به صورت پویا بر اساس ابرداده می سازیم که یک مدل شی تجاری را توصیف میکنه. می تونین آنها را بر اساس API فرم واکنشی ایجاد کنید.
فرم های محور الگوی فرم های مدل محور هستند که در آن می نویسید که منطق ، اعتبار سنجی ، کنترل و غیره را در قسمت الگوی کد با استفاده از دستورالعمل ها می نویسید. آنها برای سناریوهای ساده مناسب هستند و از اتصال دو طرفه با نحو [(ngmodel)] استفاده می کنند.
برای مثال ، می تونین با دنبال کردن مراحل ساده زیر ، فرم ثبت را به راحتی ایجاد کنید ،
FormsModule را در آرایه واردات ماژول برنامه وارد کنید
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import {FormsModule} from '@angular/forms' import { RegisterComponent } from './app.component'; @NgModule({ declarations: [ RegisterComponent, ], imports: [ BrowserModule, FormsModule ], providers: [], bootstrap: [RegisterComponent] }) export class AppModule { }
با استفاده از نحو ngmodel فرم را از الگوی به مؤلفه وصل کنید
<input type="text" class="form-control" id="name"
required
[(ngModel)]="model.name" name="name">
برای ایجاد نمونه های FormControl و ثبت آنها ، دستورالعمل NGFORM را به برچسب
<form #registerForm="ngForm">
پیام اعتبار سنجی را برای کنترل فرم اعمال کنید
<label for="name">Name</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name" #name="ngModel"> <div [hidden]="name.valid || name.pristine" class="alert alert-danger"> Please enter your name </div>
بیایید فرم را با دستورالعمل ngsubmit ارسال کنیم و دکمه نوع = "ارسال" را در پایین فرم اضافه کنیم تا فرم ارسال شود.
<form (ngSubmit)="onSubmit()" #heroForm="ngForm"> // Form goes here <button type="submit" class="btn btn-success" [disabled]="!registerForm.form.valid">Submit</button>
سرانجام ، فرم ثبت نام الگوی محور به شرح زیر ظاهر میشه.
<div class="container"> <h1>Registration Form</h1> <form (ngSubmit)="onSubmit()" #registerForm="ngForm"> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name" #name="ngModel"> <div [hidden]="name.valid || name.pristine" class="alert alert-danger"> Please enter your name </div> </div> <button type="submit" class="btn btn-success" [disabled]="!registerForm.form.valid">Submit</button> </form> </div>
در زیر تفاوت های اصلی بین اشکال واکنشی و فرم های محور الگو وجود دارد | ویژگی | واکنشی | الگوی محور | | ---- | ---- | --------- | | تنظیم مدل فرم | ایجاد شده (نمونه formcontrol) در مؤلفه صریح | ایجاد شده توسط بخشنامه ها | | به روزرسانی داده ها | همزمان | ناهمزمان | | اعتبار سنجی سفارشی | تعریف شده به عنوان توابع | تعریف شده به عنوان دستورالعمل | | تست | هیچ تعامل با چرخه تشخیص تغییر | نیاز به دانش در مورد فرآیند تشخیص تغییر | | جهش پذیری | تغییر ناپذیر (با بازگرداندن مقدار جدید برای نمونه FormControl) | قابل تغییر (خاصیت همیشه به ارزش جدید اصلاح شده) | | مقیاس پذیری | مقیاس پذیر تر با استفاده از API های سطح پایین | کمتر مقیاس پذیر به دلیل انتزاع در APIS | **[فهرست](#فهرست)**
اشکال واکنشی دو روش برای گروه بندی چندین کنترل مرتبط را ارائه می دهد.
FormGroup: یک فرم را با مجموعه ای از کنترل های ثابت تعریف میکنه که می تونن تو یک شیء با هم مدیریت شن. این ویژگی ها و روش های مشابه مشابه با یک نمونه FormControl است.
این فرم گروه می تونه برای ایجاد اشکال پیچیده مانند شکل زیر توخالی شود.
import { Component } from '@angular/core'; import { FormGroup, FormControl } from '@angular/forms'; @Component({ selector: 'user-profile', templateUrl: './user-profile.component.html', styleUrls: ['./user-profile.component.css'] }) export class UserProfileComponent { userProfile = new FormGroup({ firstName: new FormControl(''), lastName: new FormControl(''), address: new FormGroup({ street: new FormControl(''), city: new FormControl(''), state: new FormControl(''), zip: new FormControl('') }) }); onSubmit() { // Store this.userProfile.value in DB } }
<form [formGroup]="userProfile" (ngSubmit)="onSubmit()"> <label> First Name: <input type="text" formControlName="firstName"> </label> <label> Last Name: <input type="text" formControlName="lastName"> </label> <div formGroupName="address"> <h3>Address</h3> <label> Street: <input type="text" formControlName="street"> </label> <label> City: <input type="text" formControlName="city"> </label> <label> State: <input type="text" formControlName="state"> </label> <label> Zip Code: <input type="text" formControlName="zip"> </label> </div> <button type="submit" [disabled]="!userProfile.valid">Submit</button> </form>
FormArray: یک فرم پویا را در قالب آرایه تعریف میکنه ، جایی که می تونین کنترل ها را در زمان اجرا اضافه و حذف کنید. این امر برای اشکال پویا مفید است وقتی نمی دانید چه تعداد کنترل در گروه وجود خواهد داشت.
import { Component } from '@angular/core'; import { FormArray, FormControl } from '@angular/forms'; @Component({ selector: 'order-form', templateUrl: './order-form.component.html', styleUrls: ['./order-form.component.css'] }) export class OrderFormComponent { constructor () { this.orderForm = new FormGroup({ firstName: new FormControl('John', Validators.minLength(3)), lastName: new FormControl('Rodson'), items: new FormArray([ new FormControl(null) ]) }); } onSubmitForm () { // Save the items this.orderForm.value in DB } onAddItem () { this.orderForm.controls .items.push(new FormControl(null)); } onRemoveItem (index) { this.orderForm.controls['items'].removeAt(index); } }
<form [formControlName]="orderForm" (ngSubmit)="onSubmit()"> <label> First Name: <input type="text" formControlName="firstName"> </label> <label> Last Name: <input type="text" formControlName="lastName"> </label> <div> <p>Add items</p> <ul formArrayName="items"> <li *ngFor="let item of orderForm.controls.items.controls; let i = index"> <input type="text" formControlName="{{i}}"> <button type="button" title="Remove Item" (click)="onRemoveItem(i)">Remove</button> </li> </ul> <button type="button" (click)="onAddItem"> Add an item </button> </div> </form>
برای به روزرسانی خصوصیات خاص تعریف شده در مدل فرم می تونیم از روش `patchValue () استفاده کنید. برای مثال ، می تونیم نام و خیابان مشخصات خاص را با کلیک بر روی دکمه Update همانطور که در زیر آمده است ، به روز کنیم.
updateProfile() { this.userProfile.patchValue({ firstName: 'John', address: { street: '98 Crescent Street' } }); }
<button (click)="updateProfile()">Update Profile</button>
You can also use setValue
method to update properties.
Note: Remember to update the properties against the exact model structure.
FormBuilder به عنوان شکر نحوی برای ایجاد آسان نمونه هایی از یک فرمل ، فرم گروه یا فرم آررای استفاده میشه. این برای کاهش میزان دیگ بخار مورد نیاز برای ساخت اشکال واکنشی پیچیده مفید است. این به عنوان یک کلاس یاور تزریقی بسته `@angular/forms" در دسترس است.
For example, the user profile component creation becomes easier as shown here.
export class UserProfileComponent { profileForm = this.formBuilder.group({ firstName: [''], lastName: [''], address: this.formBuilder.group({ street: [''], city: [''], state: [''], zip: [''] }), }); constructor(private formBuilder: FormBuilder) { } }
شما می تونین یک ویژگی دریافت کننده (تشخیصی) رو تو داخل مؤلفه اضافه کنید تا یک نمایش JSON از مدل رو تو طول توسعه بازگرداند. این برای تأیید اینکه آیا مقادیر واقعاً از جعبه ورودی به مدل جریان دارن و برعکس یا نه ، مفید است.
export class UserProfileComponent { model = new User('John', 29, 'Writer'); // TODO: Remove after the verification get diagnostic() { return JSON.stringify(this.model); } }
and add diagnostic
binding near the top of the form
{{diagnostic}} <div class="form-group"> // FormControls goes here </div>
دستورالعمل ngModel کنترل فرم را با کلاسهای ویژه CSS انگولاری به روز میکنه تا وضعیت آن را منعکس کند. بیایید لیست کلاس ها را با فرمت جدولی پیدا کنیم ،
حالت کنترل فرم | اگر درست | اگر نادرست |
---|---|---|
بازدید | ng-touched | ng-untouched |
ارزش تغییر کرده است | ng-dirty | NG-Pristine |
ارزش معتبر است | NG-VILID | NG-Invalid |
در یک فرم مدل محور ، می تونین فرم را فقط با فراخوانی تابع "reset()" در مدل فرم ما تنظیم کنید. برای مثال ، می تونین مدل فرم را در ارسال به شرح زیر تنظیم کنید ، <span dir="ltr" align="left"> ```js onSubmit() { if (this.myform.valid) { console.log("Form is submitted"); // Perform business logic here this.myform.reset(); } } ``` </span> اوه ، مدل فرم شما فرم را به حالت بکر اصلی خود بازنشانی میکنه. **[فهرست](#فهرست)**
در اشکال واکنشی ، اعتبار سنج ها می تونن توابع sync یا async باشن ،
اعتبار سنجی همگام سازی: این توابع همزمان هستند که نمونه کنترل را می گیرند و بلافاصله مجموعه ای از خطاهای اعتبار سنجی یا تهی را برمی گردانند. همچنین ، این توابع ضمن فوری کنترل فرم ، به عنوان آرگومان دوم تصویب شدند. موارد اصلی استفاده ، چک های ساده ای هستند مانند اینکه آیا یک میدان خالی است ، خواه از حداکثر طول و غیره باشد.
اعتبار سنج های Async: این توابع ناهمزمان هستند که نمونه کنترل را می گیرند و یک وعده یا قابل مشاهده را باز می گردانند که بعداً مجموعه ای از خطاهای اعتبار سنجی یا تهی را منتشر میکنه. همچنین ، این توابع ضمن فوری کنترل فرم ، به عنوان آرگومان دوم تصویب شدند. موارد اصلی استفاده ، اعتبارسنجی پیچیده مانند ضربه زدن به سرور برای بررسی در دسترس بودن نام کاربری یا ایمیل است.
The representation of these validators looks like below
this.myForm = formBuilder.group({ firstName: ['value'], lastName: ['value', *Some Sync validation function*], email: ['value', *Some validation function*, *Some asynchronous validation function*] });
n فرم های واکنشی ، می تونین از اعتبار سنجی داخلی مانند "مورد نیاز" و "minl طول" در کنترل فرم ورودی خود استفاده کنید. برای مثال ، فرم ثبت نام می تونه این اعتبار سنج ها را در قسمت ورودی نام داشته باشد
this.registrationForm = new FormGroup({ 'name': new FormControl(this.hero.name, [ Validators.required, Validators.minLength(4), ]) });
در حالی که در فرم های الگوی محور ، هر دو اعتبار سنجی «مورد نیاز» و `minl طول به عنوان ویژگی ها موجود است.
همه validator ها پس از هر تغییر ارزش فرم اجرا میشن ، با ضربه زدن به API خارجی در هر کلید ، تأثیر عمده ای بر عملکرد با اعتبار سنج های ASYNC ایجاد میکنه. این وضعیت را می توان با تأخیر در اعتبار فرم با تغییر ویژگی UpdateON از تغییر (پیش فرض) برای ارسال یا تاری ، از آن جلوگیری کرد.
استفاده بر اساس انواع فرم متفاوت خواهد بود.
Template-driven forms: Set the property on ngModelOptions
directive
<input [(ngModel)]="name" [ngModelOptions]="{updateOn: 'blur'}">
Reactive-forms: Set the property on FormControl instance
name = new FormControl('', {updateOn: 'blur'});
بعضی اوقات ممکنه شما نیاز به ngfor و ngIf در همان عنصر داشته باشید اما متأسفانه قصد دارید در زیر خطای الگو با آن روبرو شوید.
Template parse errors: Can't have multiple template bindings on one element.
در این حالت ، شما باید از ng-container یا ng-template استفاده کنید.
اگر سعی می کنید موارد را فقط در صورت موجود بودن موارد حلقه کنید ، کد زیر خطایی رو به مرورگر ارسال میکنه
<ul *ngIf="items" *ngFor="let item of items"> <li></li> </ul>
and it can be fixed by
<ng-container *ngIf="items"> <ul *ngFor="let item of items"> <li></li> </ul> </ng-container>
از انتخاب کننده شبه کلاس "host" برای هدف قرار دادن سبک های موجود در عنصری که host مؤلفه است استفاده میشه. از آنجا که عنصر host در الگوی مؤلفه والدین قرار داره ، شما نمی تونین از طریق سایر مؤلفه ها به وسیله دیگر به عنصر host برسید.
برای مثال ، شما می تونین یک مرز برای عنصر والدین ایجاد کنین ، همانطور که در زیر وجود داره ،
//Other styles for app.component.css //... :host { display: block; border: 1px solid black; padding: 20px; }
در Angular ، یک ویژگی url از بسته روتر برای رسیدن به مسیر فعلی وجود دارد. شما باید چند مرحله زیر را دنبال کنید ،
Import Router from @angular/router
import { Router } from '@angular/router';
Inject router inside constructor
constructor(private router: Router ) { }
Access url parameter
console.log(this.router.url); // /routename
مهار مؤلفه یک API آزمایش در اطراف یک دستورالعمل یا مؤلفه انگولاری است تا با مخفی کردن جزئیات اجرای از مجموعه های آزمایش ، تست ها را ساده تر کند. این میتونه بین تست های واحد ، تست های ادغام و تست های پایان به پایان به اشتراک گذاشته شود. ایده برای مهارهای مؤلفه از الگوی pageObject که معمولاً برای آزمایش ادغام استفاده میشه ، حاصل میشه.
در طول زمان کامپایل ، Angular CLI فونت هایی ر. که برنامه ما از اون استفاده میکنه ، بارگیری و درون خطی میکنه. این به روزرسانی عملکرد اولین رنگ محتوا (FCP) رو سرعت می ده و این ویژگی به طور پیش فرض در برنامه های ساخته شده با نسخه 11 فعال میشه.
الگوییه که تو اون ما محتوا رو برای استفاده مجدد داخل یک کامپوننت دیگه وارد می کنیم.
از Content NG برای وارد کردن محتوا به صورت پویا در مؤلفه استفاده میشه که به افزایش قابلیت استفاده مجدد کامپوننت کمک میکنه.