Chuyển đến nội dung chính

Angular: Chia sẻ dữ liệu giữa các component

Trong bài viết này, mình hướng dẫn chia sẽ dữ liệu giữa Parent component, child component, và sibling component trong Angular.
Có 4 cách để chia sẽ dữ liệu:

  1. Parent to child: thông qua Input()
  2. Child to Parent: thông qua ViewChild
  3. Child to Parent: thông qua Output() và EventEmitter
  4. Giữa các component bất kỳ: thông qua Subject.

Parent to child: thông qua Input()

Giả sử chúng ta cần viết 1 trang bao gồm 2 phần tử: Parent component và child component, trong đó Parent component chứa child component như trong hình.
Vấn đề đặt ra là làm sao để truyền value “message from parent” từ Parent component tới child component?


Cách tiếp cận đơn giản nhất là dùng javascript để update DOM. Hoặc bạn dùng 1 thư viện nào khác như jQuery, AngularJs để update DOM. Khuyết điểm là có sự liên kết giữa giao diện (DOM) và business.

Thay vì liên kết trực tiếp trên DOM, bạn có thể liên kết qua business logic, cụ thể là variable được định nghĩa trong class typescript của child component.

Để có thể truyền value từ Parent component tới child component, bạn sử dụng @input() trong Child component. Ở ví dụ bên dưới, childMessage là biến dùng để nhận giá trị được truyền từ Parent component
child.component.ts

import { Component, Input, OnInit } from '@angular/core';
@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css'],
})
export class ChildComponent implements OnInit {
  @Input() childMessage: string;
  constructor() {}
  ngOnInit() {}
}

child.component.html

<h2>child works!</h2>
Say: {{ childMessage }}
parent.component.html
<h2>parent works!</h2>
Child component input: {{ childMessage }}
<app-child
  [childMessage]="parentMessage"
></app-child>
parent.component.ts
import { Component, OnInit } from '@angular/core';
import { ChildComponent } from '../child/child.component';

@Component({
  selector: 'app-parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.css'],
})
export class ParentComponent implements OnInit {
  parentMessage: string = 'message from parent';
  constructor() {}

  ngOnInit() {}

}

Child to Parent: thông qua ViewChild

Bạn sử dụng @ViewChild(<child component="">) ở Parent Component. Nhược điểm của cách này là Parent phụ thuộc vào logic của Child Component. child.component.ts
import { Component, OnInit, Output } from '@angular/core';

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css'],
})
export class ChildComponent implements OnInit {
  message: string = 'Nei hou!';
  constructor() {}

  ngOnInit() {}
}
parent.component.ts: Lưu ý bạn sử dụng ViewChild ở hàm ngAfterViewInit()
import { Component, OnInit, ViewChild } from '@angular/core';
import { ChildComponent } from '../child/child.component';

@Component({
  selector: 'app-parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.css'],
})
export class ParentComponent implements OnInit {
  @ViewChild(ChildComponent) child;
  childMessage: string;
  constructor() {}

  ngOnInit() {}

  ngAfterViewInit() {
    this.childMessage = this.child.message;
  }
}

Child to Parent: thông qua Output() và EventEmitter

Cách sử dụng ViewChild() có khuyết điểm là nếu Child Component thay đổi tên biến thì Parent Component cũng phải sửa đổi theo. Ngoài ra nếu bạn muốn update realtime thì sẽ rất khó khăn.

Cách ở trên là liên kết trực tiếp với nhau. Có 1 giải pháp mềm dẻo hơn là sử dụng EventEmitter(). Dữ liệu sẽ được emit từ Child component, và được lắng nghe bởi Parent component.

Ở Parent component, bạn tạo hàm receiveMessage() để nhận data từ event emit().

Ở Child component, bạn khai báo @Output() messageEvent = new EventEmitter<string>();

Ở trang html của Parent component, bạn subscribe messsageEvent = receiveMessage($event). Bất cứ khi nào ở Child component emit data thì hàm receiveMessage sẽ nhận được trigger và update cho Parent component.

child.component.ts

import { Component, EventEmitter, OnInit, Output } from '@angular/core';

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css'],
})
export class ChildComponent implements OnInit {
  message: string = 'Nei hou!';
  @Output() messageEvent = new EventEmitter<string>();
  constructor() {}

  ngOnInit() {}

  onClickTest() {
    const d = new Date();
    this.message = d.toString();
    console.log(this.message);
    this.sendMessage();
  }

  sendMessage() {
    this.messageEvent.emit(this.message);
  }
}
child.component.html
<h2>child works!</h2>
<button (click)="onClickTest()">Click here</button>
parent.component.ts
iimport { Component, OnInit } from '@angular/core';
import { ChildComponent } from '../child/child.component';

@Component({
  selector: 'app-parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.css'],
})
export class ParentComponent implements OnInit {
  childMessage: string;
  constructor() {}

  ngOnInit() {}

  receiveMessage($event) {
    this.childMessage = $event;
  }
}
Parent.component.html
<h2>parent works!</h2>
Child component input: {{ childMessage }}
<app-child (messageEvent)="receiveMessage($event)"
></app-child>

Giữa các component bất kỳ: thông qua Subject.

Khi chia sẽ data giữa các component bất kỳ, bạn nên sử dụng shared service. Trong shared service, bạn định nghĩa BehaviorSubject. BehaviorSubject cho phép bạn nhận các giá trị từ thời điểm nó subcribe. Mỗi khi có data mới, các subscriber sẽ nhận được giá trị mới nhất.

 

Dựa vào sơ đồ trên, chúng ta sẽ code từ DataService trước.

data.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
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, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import { DataService } from '../../services/data.service';

@Component({
  selector: 'app-parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.css'],
})
export class ParentComponent implements OnInit, OnDestroy {
  message: string;
  subscription: Subscription;

  constructor(private dataService: DataService) {}

  ngOnInit() {
    this.subscription = this.dataService.currentMessage.subscribe(
      (message) => (this.message = message)
    );
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}
parent.component.html
<p>parent works!</p>
{{ message }}
Tương tự với file sibling.component nhưng chúng ta sẽ thêm nút NewMessage sibling.component.html
<p>sibling works!</p>
{{ message }}
<button (click)="newMessage()">New Message</button>
sibling.component.ts
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import { DataService } from '../../services/data.service';

@Component({
  selector: 'app-sibling',
  templateUrl: './sibling.component.html',
  styleUrls: ['./sibling.component.css'],
})
export class SiblingComponent implements OnInit, OnDestroy {
  message: string;
  subscription: Subscription;

  constructor(private dataService: DataService) {}

  ngOnInit() {
    this.subscription = this.dataService.currentMessage.subscribe(
      (message) => (this.message = message)
    );
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }

  newMessage() {
    const d = new Date();
    const message = d.toString();
    this.dataService.changeMessage('Hello from Sibling in ' + message);
  }
}

Bạn sẽ có kết quả như sau:

Tham khảo

 
Chúc các bạn thành công!

Nhận xét

Bài đăng phổ biến từ blog này

[ASP.NET MVC] Authentication và Authorize

Một trong những vấn đề bảo mật cơ bản nhất là đảm bảo những người dùng hợp lệ truy cập vào hệ thống. ASP.NET đưa ra 2 khái niệm: Authentication và Authorize Authentication xác nhận bạn là ai. Ví dụ: Bạn có thể đăng nhập vào hệ thống bằng username và password hoặc bằng ssh. Authorization xác nhận những gì bạn có thể làm. Ví dụ: Bạn được phép truy cập vào website, đăng thông tin lên diễn đàn nhưng bạn không được phép truy cập vào trang mod và admin.

ASP.NET MVC: Cơ bản về Validation

Validation (chứng thực) là một tính năng quan trọng trong ASP.NET MVC và được phát triển trong một thời gian dài. Validation vắng mặt trong phiên bản đầu tiên của asp.net mvc và thật khó để tích hợp 1 framework validation của một bên thứ 3 vì không có khả năng mở rộng. ASP.NET MVC2 đã hỗ trợ framework validation do Microsoft phát triển, tên là Data Annotations. Và trong phiên bản 3, framework validation đã hỗ trợ tốt hơn việc xác thực phía máy khách, và đây là một xu hướng của việc phát triển ứng dụng web ngày nay.

Tổng hợp một số kiến thức lập trình về Amibroker

Giới thiệu về Amibroker Amibroker theo developer Tomasz Janeczko được xây dựng dựa trên ngôn ngữ C. Vì vậy bộ code Amibroker Formula Language sử dụng có syntax khá tương đồng với C, ví dụ như câu lệnh #include để import hay cách gói các object, hàm trong các block {} và kết thúc câu lệnh bằng dấu “;”. AFL trong Amibroker là ngôn ngữ xử lý mảng (an array processing language). Nó hoạt động dựa trên các mảng (các dòng/vector) số liệu, khá giống với cách hoạt động của spreadsheet trên excel.