تا به اینجای کار مباحث مربوط به databinding و نحوهی ارتباط کاربر با کنترلر و کنترلر با کاربر را فرا گرفتید و با مثالی که خدمت شما عزیزان ارائه کردیم مفاهیمی چون رویدادها (events) و two-way databinding یا ارتباطات دو طرفه را آموزش دادیم. حال در این بخش میخواهیم به دستورهای شرطی و کنترلی و همچنین دستورهای (directive) پرکاربرد انگولار بپردازیم تا مقدمهای برای ورود به دنیای حرفهای فریم ورک قدرتمند انگولار فراهم کرده باشیم. با ما همراه باشید.
Directives به عنوان یک سری دستورالعملها هستند که درون DOM مورد استفاده قرار میگیرند. دستورها به صورت کلی در قالبها (فایلهای component.html) اعمال میشوند و بهگونهای دستورهای شرطی کنترلی و ظاهری به فضای قالب شما اضافه میکنند. به عنوان مثال عبارت زیر به صورت یک directive شناخته میشود:
<a appTurnGreen>Receive a Green Background!</p>
و سپس با تعریف یک مفسر به نام Directive@ درون کامپوننت میتوان این Directive یا دستورالعمل را برای این تگ p معرفی کرد که به صورت زیر در کامپوننت تعریف میشود:
@Directive({ selector: '[appTurnGreen]' }) export class TurnGreenDirective{ }
در تعریف فوق به صورت کلی یک دستورالعمل را توسط مفسر به کامپوننت معرفی کردیم. حال در ادامه به دستورالعمل ساختهشده توسط خود انگولار میپردازیم.
از نام این دستور مشخص است که یک دستور شرطی بوده و متناسب با قید و شرطی که برای آن تعیین میکنیم باعث نمایش دادن آن تگ خواهد شد.
البته این دستورها در قالب HTML و سمت کاربر مورد استفاده قرار میگیرند شکل نوشتاری این دستور در انگولار به صورت زیر است:
*ngIf = "condition expression"
این دستور از یک عبارت ngIf* و علامت انتساب (=) و سپس عبارت شرطی که میتواند به صورت Ture و False باشد. یعنی اگر عبارت شرطی برابر True گردد، تگی که این دستورالعمل در آن بکار گرفته شده است، فعال خواهد شد.
علامت ستاره * در این دستور به این معنیست که دستور ngIf یک دستور ساختاری (Structural) بوده و المانهای DOM را تحت تاثیر قرار میدهد.
توجه: دستورهای ساختاری یا Structural به دستورهایی گفته میشود که در المانهای DOM یک صفحه تغییراتی ایجاد کنند مثلا یک المان را حذف و یا اضافه کنند.
برای درک بیشتر این دستور مثال قبل را با یکدیگر بررسی میکنیم. در فایل servers.component.html ابتدا تغییراتی را لحاظ میکنیم که این تغییرات تنها شامل اضافه کردن یک جفت تگ <p> است:
<label> نام سرور</label> <input type="text" class="form-control" [(ngModel)]="serverName" > <p>{{serverName}}</p> <button class="btn btn-primary" [disabled]="!allowNewServer" (click)="onCreateServer()">سرور جدید</button> <!--<p>{{ serverCreationStatus }}</p>--> <p *ngIf="serverCreation">سرور جدید با موفقیت اضافه شد نام سرور: {{serverName}}</p> <app-server></app-server> <app-server></app-server>
همچنین تغییراتی را برای فایل servers.component.ts در نظر میگیریم که به صورت زیر خواهد بود:
import {Component, OnInit} from '@angular/core'; @Component({ selector: 'app-servers', templateUrl: './servers.component.html', styleUrls: ['./servers.component.css'] }) export class ServersComponent implements OnInit { allowNewServer: boolean = false; serverCreationStatus: string = "سروری ایجاد نشده است"; serverName: string = 'سرور شماره ۱'; serverCreation: boolean = false; constructor() { setTimeout(() => { this.allowNewServer = true; }, 2000); } ngOnInit() { } onCreateServer() { this.serverCreation = true; this.serverCreationStatus = 'سرور جدید با موفقیت ایجاد شد و نام این سرور برابر است با: ' + this.serverName; } onUpdateServerName(event: Event) { this.serverName = (<HTMLInputElement>event.target).value; } }
با بررسی کد فوق متوجه خواهید شد که یک متغییر به نام serverCreation ایجاد کردهایم و مقدار پیشفرض آن را برابر false قرار دادهایم. سپس داخل متد onCreateServer این متغییر را به true تغییر داده ایم. یعنی کاربر با فشردن دکمهی «سرور جدید» مقدار Ture را دریافت و در نهایت تگ <p> نمایش داده خواهد شد.
این دستور به عنوان یک ساختار شرطی میباشد که در صورت برقرار نبودن شرط if یک سری تگ دیگر را نمایش میدهد.
برای تعریف دستور else به صورت زیر عمل میکنیم:
<p *ngIf="condition expression; else noServer">...</p> <ng-template #noServer> <p>...</p> </ng-template>
یک قالب داخلی به نام ng-template ساخته و صفتی به عنوان نام آن، مشخص کردهایم (noServer) سپس در دستورات شرطی گفتهایم که اگر شرط برقرار نبود در غیر اینصورت (else) قالب noServer را نمایش بده!
این دستور را میتوانید در مثال قبلی تکرار کنید تا آن را مورد بررسی قرار دهید. بنابراین ابتدا فایل servers.component.html را باز کرده و سپس ویرایش زیر را در آن انجام میدهیم:
<label> نام سرور</label> <input type="text" class="form-control" [(ngModel)]="serverName" > <p>{{serverName}}</p> <button class="btn btn-primary" [disabled]="!allowNewServer" (click)="onCreateServer()">سرور جدید</button> <!--<p>{{ serverCreationStatus }}</p>--> <p *ngIf="serverCreation; else noServer">سرور جدید با موفقیت اضافه شد نام سرور: {{serverName}}</p> <ng-template #noServer> <p>سرور جدیدی اضافه نشده است</p> </ng-template> <app-server></app-server> <app-server></app-server>
این دستور یک دستور صفتی (attribute directive) میباشد که ظاهر (style) یک تگ یا المان را تغییر میدهد.
ساختار کلی آن به صورت زیر است:
<p [ngStyle] = "{cssAttribute: value}"></p>
برای روشن تر شدن این موضوع مثال قبلی را ادامه میدهیم.
در واقع میخواهیم برای وضعیت سرور (serverStatus) یک رنگ تعریف کرده بگونهای که اگر وضعیت سرور خاموش بود رنگ آن قرمز و اگر وضعیت سرور روشن بود رنگ آن را سبز قرار دهیم.
برای اینکار ابتدا یک تابع random انتخاب کرده و سپس شرطی برای آن درج میکنیم. در نهایت در فایل server.component.html دستور صفتی ngStyle را به صورت یک ویژگی (property) به کنترلر ارسال (bind) میکنیم. بنابراین توجه داشته باشید که علامت براکت [] در این دستور جزئی از دستور صفتی ngStyle نیست بلکه به معنای بایند (ارسال) یک ویژگی به کنترلر مورد استفاده قرار میگیرد.
بنابراین داریم:
توجه: دستورهای صفتی یا attribute به دستورهایی گفته میشود که در المانهای DOM یک صفحه تغییراتی ایجاد نکنند مثلا با اعمال آنها تنها صفات یک تگ تغییر کند و آن تگ حذف یا اضافه نشود.
ابتدا فایل server.component.ts را باز کرده و تغییرات زیر را در آن لحاظ میکنیم:
import {Component} from "@angular/core" @Component({ selector: 'app-server', templateUrl: "./server.component.html" }) export class ServerComponent { serverId: number = 10; serverStatus: string = ""; constructor() { this.serverStatus = Math.random() > 0.5 ? 'روشن' : 'خاموش'; } getServerStatus() { return this.serverStatus; } getColor() { return this.serverStatus === "روشن" ? "green" : "red"; } }
حال در فایل server.component.html نیز تغییرات دیگری را جهت استفاده از این دستور صفتی اعمال میکنیم. برای اضافه کردن یک ویژگی css ابتدا باید یک جفت کروشه ویژگی جاوا اسکریپت { } ایجاد کرده و سپس درون آن یا مقادیر صفات css را نوشته و یا یک صفت را به یک تابع که در فایل server.component.ts ایجاد کردهایم، ارجاع دهیم:
<p [ngStyle]="{backgroundColor: getColor()}">وضعیت {{'سرور'}} با ID: {{serverId}} برابر است با: {{getServerStatus()}}</p>
در صورتیکه موارد فوق را به درستی انجام داده باشید خروجی شما به صورت زیر خواهد بود:
این دستور نیز مشابه دستور ngStyle یک دستور صفتی (attribute directive) بوده و در نهایت تغییرات ظاهری (style) روی تگ یا المان موردنظر اعمال میکند.
با استفاده از این دستور میتوان یک کلاس خاص را به یک تگ لحاظ کرد. ساختار کلی این دستور به صورت زیر است:
<p [ngClass] = "{cssClass: condition to active}"></p>
برای مثال همانند قبل یک ویژگی (property) جهت ارسال اطلاعات از کنترلر به سمت کاربر، تعریف خواهیم کرد و در نهایت یک استایل برای یک class. سی اس اس خاص اعمال میکنیم.
بنابراین برای کامپوننت server که آن را قبلا به صورت دستی ساخته بودیم ابتدا یک فایل تحت عنوان server.component.css ایجاد کرده و در نهایت یک کلاس با نام online درون آن تعریف میکنیم. بنابراین این فایل خواهیم داشت:
.online{ color: yellow; }
سپس در فایل server.component.ts نیز این css را به کامپوننت اضافه میکنیم بنابراین این فایل به صورت زیر تغییر میکند:
import {Component} from "@angular/core" @Component({ selector: 'app-server', templateUrl: "./server.component.html", styleUrls: ["./server.component.css"] }) export class ServerComponent { serverId: number = 10; serverStatus: string = ""; constructor() { this.serverStatus = Math.random() > 0.5 ? 'روشن' : 'خاموش'; } getServerStatus() { return this.serverStatus; } getColor() { return this.serverStatus === "روشن" ? "green" : "red"; } }
و در نهایت آنچه درون فایل server.component.html اعمال خواهیم کرد به صورت زیر میباشد:
<p [ngStyle]="{backgroundColor: getColor()}" [ngClass]="{online: serverStatus === 'روشن'}" > وضعیت {{'سرور'}} با ID: {{serverId}} برابر است با: {{getServerStatus()}} </p>
در واقع در این حالت به سیستم میگوییم که اگر serverStatus برابر «روشن» بود آنگاه کلاس online. را از فایل css درون کامپوننت فعال کرده و سپس class=online را به المان DOM اضافه کن.
در صورتیکه این کار را به درستی انجام داده باشید با خروجی زیر روبهرو خواهید شد:
همانطور که ملاحظه کردید کلاس موردنظر اعمال و در نهایت فایل css که درون کامپوننت server.component.ts نوشته بودیم فعال و نمایش داده میشود.
این دستور یک همانند دستور ngIf یک دستور ساختاری (Structural Directive) بوده و با اعمال آن برای یک آرایه، المانهایی را تکرار میکند.
مثلا فرض کنید میخواهیم ده عدد تگ <P> برای یک شرایط خاص ایجاد کنیم آنگاه بجای تکرار ۱۰ باره این تگ، کافیست از دستور ngFor استفاده کرده و در یک خط دستور تکرار ۱۰ باره المان را بدهیم. ساختار کلی این دستور به صورت زیر است:
<p *ngFor = "let item of items"></p>
در این دستور به ترتیب داریم:
برای روشنتر شدن مفهوم این دستور ابتدا یک تغییر به فایل servers.component.ts داده و آرایهای از اسامی سرورها را ایجاد و در نهایت درون متغییر server قرار میدهیم.
سپس میخواهیم کاری کنیم که وقتی کاربر روی دکمهی «سرور جدید» کلیک کرد اسامی که درون فرم نوشتهشده است به متغییر server اضافه و در نهایت آنها را در صفحه نمایش دهیم.
بنابراین در فایل servers.component.ts داریم:
import {Component, OnInit} from '@angular/core'; @Component({ selector: 'app-servers', templateUrl: './servers.component.html', styleUrls: ['./servers.component.css'] }) export class ServersComponent implements OnInit { allowNewServer: boolean = false; serverCreationStatus: string = "سروری ایجاد نشده است"; serverName: string = ''; serverCreation: boolean = false; servers: string[] = ["سرور روکسو", "سرور اختصاصی روکسو"]; constructor() { setTimeout(() => { this.allowNewServer = true; }, 2000); } ngOnInit() { } onCreateServer() { this.serverCreation = true; this.servers.push(this.serverName); this.serverCreationStatus = 'سرور جدید با موفقیت ایجاد شد و نام این سرور برابر است با: ' + this.serverName; } onUpdateServerName(event: Event) { this.serverName = (<HTMLInputElement>event.target).value; } }
توجه داشته باشید که از دستور push برای اضافه کردن اسامی که داخل فرم نوشته میشود به آرایهی server استفاده کردهایم.
حال فایل مربوط به servers.component.html را نیز به صورت زیر تغییر خواهیم داد:
<label> نام سرور</label> <input type="text" class="form-control" [(ngModel)]="serverName" > <p>{{serverName}}</p> <button class="btn btn-primary" [disabled]="!allowNewServer" (click)="onCreateServer()">سرور جدید</button> <!--<p>{{ serverCreationStatus }}</p>--> <p *ngIf="serverCreation; else noServer">سرور جدید با موفقیت اضافه شد نام سرور: {{serverName}}</p> <ng-template #noServer> <p>سرور جدیدی اضافه نشده است</p> </ng-template> <app-server *ngFor="let server of servers"></app-server>
اگر در خروجی به ازای هر اسمی که درون فرم مینویسید دکمهی «سرور جدید» را بفشارید در نهایت یک المان DOM به صفحه شما اضافه خواهد شد که حال حلقهی ngFor است. بنابراین خروجی به صورت زیر خواهد بود:
توجه به این نکته ضروریست که برای دستیابی به شمارهی ایندکسها در یک حلقه for در انگولار میتوان با تعریف یک متغییر مانند i بعد از عبارت موجود در دستور، به این شمارش دست پیدا کرد.
<p *ngFor = "let item of items; let i = index"></p>
بسیار عالی! به شما عزیزان تبریک میگوییم. در این بخش با برخی از دستورهای صفتی و ساختاری موجود در انگولار آشنا شدید. توجه داشته باشید که این دستورها فقط به همین تعداد خلاصه نمیشوند و در فصول آینده قطعا با عمق بیشتری به آنها خواهیم پرداخت. روند آموزشی بدین صورت است که ابتدا مقدمات و ملزومات را مطرح و سپس در هر بخش عمیقتر خواهیم شد. با ما همراه باشید.
توجه: دوستان عزیز آموزش ویدیویی انگولار 6 از مقدماتی تا پیشرفته به زبان فارسی را میتوانید با کلیک روی اینجا یاد بگیرید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.