برای مدیریت بهتر پروژه در انگولار، نیاز است شما پروژه خود را به کامپوننت های کوچک خرد کنید. وقتی اینکار را انجام دادید نیاز است تا داده بین کامپوننت ها منتقل شود.
پنج شیوه برای انتقال داده بین کامپوننت ها وجود دارد.
- کامپوننت والد به کامپوننت فرزند
- کامپوننت فرزند به کامپوننت والد
- انتقال داده بین کامپوننت های خواهر و برادر
- انتقال داده با استفاده از پراپرتی ViewChild
- انتقال داده بین کامپوننت هایی که بهم مرتبط نیستند
1. کامپوننت والد به کامپوننت فرزند: این شیوه شاید رایج ترین و سرراست ترن شیوه انتقال داده باشد. در این شیوه با استفاده از دکوراتور @Input() داده ها منتقل میشوند.
parent.component.ts
import { Component } from '@angular/core'; @Component({
selector: 'app-parent',
template: `
<app-child [childMessage]="parentMessage"></app-child>
`,
styleUrls: ['./parent.component.css']
})
export class ParentComponent{
parentMessage = "message from parent"
constructor() { }
}
child.component.ts
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-child',
template: `
Say {{ message }}
`,
styleUrls: ['./child.component.css']
})
export class ChildComponent {
@Input() childMessage: string;
constructor() { }
}
2. کامپوننت فرزند به کامپوننت والد: شیوه دیگر انتقال داده خارج کردن داده از فرزند است. اگر بخواهید داده های درون کامپوننت فرزند که بر اثر کلیک بر روی یک دکمه، ورودی های فرم، و یا دیگر eventها تغییر کرده اند را به کامپوننت والد منتقل کنید میتوانید از این شیوه استفاده کنید.
در والد، فانکشنی برای دریافت پیام ایجاد میکنیم و آنرا با متغییر پیام برابر میکنیم. در فرزند، متغییر messageEvent با دکورتور @Output() تعریف میکنیم و آنرا برابر با event emitter میکنیم. سپس فانکشنی با نام sendMessage ایجاد میکنیم تا برای این event پیام مارا emit کند. در نهایت، دکمه ای میسازیم که این فانکشن را فراخوانی کند.
اکنون کامپوننت والد به این messageEvent سابسکرایب شده است و هر زمان که فانکشن اجرا شود متوجه میشود.
parent.component.ts
import { Component } from '@angular/core'; @Component({
selector: 'app-parent',
template: `
Message: {{message}}
`,
styleUrls: ['./parent.component.css']
})
export class ParentComponent { constructor() { } message:string; receiveMessage($event) {
this.message = $event
}
}
child.component.ts
import { Component, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-child',
template: `
<button (click)="sendMessage()">Send Message</button>
`,
styleUrls: ['./child.component.css']
})
export class ChildComponent {
message: string = "Hola Mundo!"
@Output() messageEvent = new EventEmitter();
constructor() { }
sendMessage() {
this.messageEvent.emit(this.message)
}
}
3. انتقال داده بین کامپوننت خواهر و برادر: انتقال داده بین کامپوننت خواهر و برادر میتواند با استفاده از موارد 1 و 2 انجام شود. ابتدا داده با استفاده از کامپوننت فرزند به والد و استفاده از دکوراتور @Output و EventEmitter منتقل میشود. زمانی که داده به کامپوننت والد میرسد با استفاده از دکوراتور @Input به یک کامپوننت فرزند دیگر منتقل میشود. به عبارت دیگر، کامپوننت های خواهر و برادر از طریق کامپوننت والد با یکدیگر ارتباط دارند.
4. انتقال داده با استفاده از دکوراتور ViewChild: دکوراتور ViewChild به کامپوننت این اجازه را میدهد تا یک کامپوننت درون کامپوننت دیگر inject شود و بنابراین کامپوننت والد به اتریبیوت ها و فانکشنهای آن کامپوننت دسترسی پیدا میکند. تنها یک مشکل دارد و آن این است که کامپوننت فرزند تا زمانی که initialize نشده باشد قابل دسترس نیست. بنابراین نیاز است تا ما AfterViewInit lifecycle را اضافه کنیم تا به داده های فرزند دسترسی پیدا کنیم.
parent.component.ts
import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { ChildComponent } from "../child/child.component";
@Component({
selector: 'app-parent',
template: `
Message: {{ message }}
<app-child></app-child>
`,
styleUrls: ['./parent.component.css']
})
export class ParentComponent implements AfterViewInit {
@ViewChild(ChildComponent) child;
constructor() { }
<message:string;
ngAfterViewInit() {
this.message = this.child.message
}
}
child.component.ts
import { Component} from '@angular/core';
@Component({
selector: 'app-child',
template: `
`,
styleUrls: ['./child.component.css']
})
export class ChildComponent {
message = 'Hola Mundo!';
constructor() { }
}
5. انتقال داده بین کامپوننت هایی که بهم مرتبط نیستند برای انتقال داده بین کامپوننت هایی که ارتباط مستقیم باهم ندارند از share service استفاده میکنیم. اگر قرار است داده شما همواره sync باشد استفاده از RxJs BehaviorSubject بهترین گزینه است، زیرا:
- همواره مقدار current را در subscription بر میگرداند – نیازی به فراخوانی onnext نیست
- فانکشن getValue() را برای گرفتن آخرین مقدار دارد
- کامپوننت همواره آخرین دیتا را دریافت میکند
در سرویس، ما یک private BehaviorSubject میسازیم که مقدار current را نگه میدارد. ما متغییر currentMessage را که استریم دیتا را بصورت یک observable نگه میدارد تعریف میکنیم. در نهایت، فاکنشنی که متد next را فراخوانی میکند مینویسیم تا مقدار را تغییر دهد.
کامپوننت والد، کامپوننت فرزند، کامپوننت های خواهر و برادر، همه یک رفتار را دریافت میکنند.
ما DataService را در کانستراکتور inject میکنیم، سپس subscribe میکنیم به currentMessage و مقدار آنرا برابر با متغییر message میکنیم.
اکنون، اگر فانکشنی در هر یک از این کامپوننت ها بنویسیم که مقدار پیام را تغییر دهد، زمانی که فاکنشن اجرا شود داده جدید بصورت خودکار به همه کامپوننت ها منتشر میشود.
data.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Injectable()
export class DataService {
private messageSource = new BehaviorSubject('default message');
currentMessage = this.messageSource.asObservable();
constructor() { }
changeMessage(message: string) {
this.messageSource.next(message)
}
}
parent.component.ts
import { Component, OnInit } from '@angular/core';
import { DataService } from "../data.service";
@Component({
selector: 'app-parent',
template: `
{{message}}
`,
styleUrls: ['./sibling.component.css']
})
export class ParentComponent implements OnInit {
message:string;
constructor(private data: DataService) { }
ngOnInit() {
this.data.currentMessage.subscribe(message => this.message = message)
}
}
sibling.component.ts
import { Component, OnInit } from '@angular/core';
import { DataService } from "../data.service";
@Component({
selector: 'app-sibling',
template: `
{{message}}
<button (click)="newMessage()">New Message</button>
`,
styleUrls: ['./sibling.component.css']
})
export class SiblingComponent implements OnInit {
message:string;
constructor(private data: DataService) { }
ngOnInit() {
this.data.currentMessage.subscribe(message => this.message = message)
}
newMessage() {
this.data.changeMessage("Hello from Sibling")
}
}
محمد صالح کاتبی دوازدهم سپتامبر 2020