12/08/2018, 14:28

Tìm hiểu Pipes trong Angular 2

*Chào các bạn! Trong bài viết hôm nay mình sẽ cùng nhau về Pipes trong Angular 2* I/ Khái niệm Pipes Nếu copy Pipe và đem paste vào google translate để dịch thì có nghĩa là ống nước. Ống nước thì có liên quan gì ở đây (yaoming) Vui vậy thôi, chứ Pipe trong Angular 2 là: một cách mới để ...

*Chào các bạn!

Trong bài viết hôm nay mình sẽ cùng nhau về Pipes trong Angular 2*

I/ Khái niệm Pipes

  • Nếu copy Pipe và đem paste vào google translate để dịch thì có nghĩa là ống nước. Ống nước thì có liên quan gì ở đây (yaoming)
  • Vui vậy thôi, chứ Pipe trong Angular 2 là: một cách mới để filter dữ liệu xuất hiện trong angular version 2, nó thay thế filters trong Angular 1

Để hiểu rõ hơn về pipes thì chúng ta đến với các phần tiếp theo nha

II/ Sử dụng Pipes

  • Giống như filter, Pipes cũng cần dữ liệu input để transform ra output mình mong muốn
  • Ví dụ:
import { Component } from '@angular/core';

@Component({
  selector: 'product-price',
  template: `<p>Total price of product is {{ price | currency }}</p>`
})
export class ProductPrice {
  price = 100.1234;
}

Giải thích:

  • Như cách sử dụng mình đã đề cập ở trên, Input là biến price với giá trị như đã gán trong class ProductPrice.
  • Chúng ta sử dụng Pipes currency để transform(biến đổi, thay đổi) data như mình mong muốn. Cái mình mong muốn ở đây là: thêm đơn vị tiền tệ vào price
  • Khi chạy thì expected mình mong muốn là: Total price of product is USD100.12
  • Link full source code demo cho ví dụ này

Làm tới đây thì các bạn sẽ đặt câu hỏi là, mình có thể truyền được Parameters vào Pipes đây? À, mình sẽ hướng dẫn cho các bạn luôn. Các bạn theo dõi tiếp nha

  • Để truyền được param vào thì các bạn tuân thủ theo cú pháp sau nha:
pipeName: paramterValue

Mở rộng thêm, nếu truyền vào nhiều params vào thì chúng ta phải tuân thủ theo cú pháp sau

pipeName: parameter1: parameter2: paramter3

-> Với syntax này thì các bạn chú ý dấu 2 chấm nhé

  • Ví dụ
import { Component } from '@angular/core';

@Component({
    selector: 'app-root',
    template: '<p>Total price of product is {{ price | currency: "VND" }}</p>'
})
export class AppComponent {
  price = 100.123456;
}
  • Với ví dụ trên thì input là giá tiền, pipes là currency, và param mình muốn truyền vào là "VND"
  • Khi chạy đoạn code trên thì kết quả sẽ là: Total price of product is ₫100.1235

Phần truyền Multi params thì các bạn cũng làm tương tự như truyền 1 param với syntax như ở trên mình giới thiệu nha các bạn

Truyền nhiều Params vào trong 1 Pipes được rồi, thì liệu có thể sử dụng nhiều Pipes cùng lúc được không, đây cũng là một câu hỏi hay. Mình xin trả lời trước là được, vậy sử dụng như thế nào, cú pháp ra sao thì mời các bạn theo dõi tiếp nha.

  • Trước hết, mời các bạn theo dõi ví dụ sau đây nha.
import { Component } from '@angular/core';

@ Component({
    selector: 'app-root',
    template: '<p>Total price of product is {{ price | currency: "VND" | lowercase }}</p>'
})
export class ProductPrice {
  price = 100.123456;
}

Giải thích:

  • Với đoạn code trong phần template trong component ở trên thì chúng ta có thể thấy vài điều như thế này:
  • input là price
  • pipes: currency và lowercase
  • param truyền vào: VND
  • Kết quả sau khi chạy đoạn code trên sẽ là: Total price of product is vnd100
  • Link full source code demo cho ví dụ này

-> Rút ra là: để sử dụng nhiều pipes trong một expression thì chúng phân cách bằng dấu | (giống như phân cách giữa input và pipeName)

Sau khi mình giới thiệu một vài nét cơ bản về Pipes trong Angular 2 thì chắc hẳn là các bạn đã hiểu được phần nào rồi đúng không. Chúng ta đến với phần tiếp theo

III/ Custom Pipes

  • Angular 2 cho phép chúng ta tạo được các Pipe của riêng chúng ta để Filter dữ liệu theo ý đồ của mình
  • Trước hết các bạn hãy xem các ví dụ sau, mình sẽ giải thích dựa trên ví dụ này để các bạn dễ hiểu hơn nhé
  • Giả sử chúng ta có một object channel, có các thuộc tính sau
export class Channel {
    id: number;
    channel_category_id: number;
    company_id: number;
    identifier: string;
    name: string;
    description: string;
    device_type: string;
    auth_type: string;
    auth_driver: string;
    auth_driver_arguments: string;
    status: number;
    public: boolean;
    sort: number;
    created_at: string;
}
  • Đây là Pipe của chúng ta định nghĩa
import { Pipe, PipeTransform } from '@angular/core';
import { Channel } from "./channel";

@Pipe({
    name: 'ChannelFilterPipe',
})

export class ChannelFilterPipe implements PipeTransform{
    transform(channels: Channel[], input: any) {
        if (input !== ') {
            return channels.filter(channel =>
                channel.identifier.startsWith(input) ||
                channel.identifier.includes(input) ||
                channel.identifier === input ||

                channel.name.startsWith(input) ||
                channel.name.includes(input) ||
                channel.name === input ||

                channel.device_type.startsWith(input) ||
                channel.device_type.includes(input) ||
                channel.device_type === input ||

                channel.auth_type.startsWith(input) ||
                channel.auth_type.includes(input) ||
                channel.auth_type === input ||

                channel.auth_driver.startsWith(input) ||
                channel.auth_driver.includes(input) ||
                channel.auth_driver === input
            );
        }

        return channels;
    }
}

Giải thích:

  • Đầu tiên để pipes hoạt động mà không bị lỗi gì thì chúng ta cần import thư viện core của angular support cho Pipes vào, cụ thể ở ví dụ trên là: Pipe và PipeTransform
  • Tiếp theo, chúng ta @Pipe decorator, định nghĩa thuộc tính name , name ở đây là tên Pipes. Tên này sẽ được gọi(sử dụng) trong template expressions. Như các bạn thấy trong ví dụ trên
  • Tiếp theo nữa là, định nghĩa một class, class này bắt buộc phải implement method tranforms của PipeTransform interface.
  • Method transform sẽ có các đối sô, đối số thứ nhất là: đối tượng Channel đã định nghĩa ở trên, đối số thứ 2 là input(giá trị người dùng nhập vào để filter)
  • Trong phần thân của method transform sẽ xử lý như sau:

1. Phần người dùng nhập 1 input bất kỳ thì sẽ check xem input đó có match với thuộc tính nào của đối tượng channel hay không

2. Có thể check bằng các method như: startWith, include, hoặc =

3. Nếu có kết quả phù hợp thì sẽ trả về cho người dùng

=> Toàn bộ phần code ở ví dụ trên đã thực hiện được việc như mình giải thích ở trên

IV/ Stateful Pipes

Có 2 loại pipes, đó là:

  • Stateless pipe, là những pipe sử dụng input data mà không cần ghi nhớ, không lưu trữ gì sau khi thực hiện xong nhiệm vụ. Ví dụ CurrencyPipe mà chúng ta đã sử dụng ở ví dụ đầu tiên là Stateless pipe.
  • Ngược lại với stateless pipe, Stateful pipelà những pipe mà có thể quản lý được dữ liệu sau khi biến đổi, thay đổi. Loại pipes này có thể tạo ra HTTP request, lưu trữ Response và cuối cùng là hiển thị output. Chính vì điều này nên chúng ta nên cẩn thận khi sử dụng loại pipe này

Angular 2 cung câp thư viện AsyncPipe để làm việc với stateful pipe

  • AsyncPipe có thể nhận giá trị kiểu Promise hoăc Observable như là input data và sẽ tự động subcribe input này

Ví dụ sử dụng kiểu promise

@Component({
  selector: 'app-root',
  template: `
    <p>Total price of product is {{fetchPrice | async | currency:"CAD"}}</p>
    <p>Seconds: {{seconds | async}} </p>
  `
})
export class AppComponent {
  fetchPrice = new Promise((resolve, reject) => {
    setTimeout(() => resolve(10), 500);
  });

  seconds = Observable.of(0).concat(Observable.interval(1000))
}

Link source code tham khảo

Implementing Stateful Pipes

Để implement stateful pipe chúng ta set thuộc tính pure trong @Pipebằng false.

Để hiểu được điều này, chúng ta đến với ví dụ tiếp theo. Trong ví dụ này, chúng ta sẽ dùng dữ liệu kiểu Observable

// naive implementation assumes small number increments
@Pipe({
  name: 'animateNumber',
  pure: false
})
export class AnimateNumberPipe implements PipeTransform {
  private currentNumber: number = null; // intermediary number
  private targetNumber: number = null;

  transform(targetNumber: number): string {
    if (targetNumber !== this.targetNumber) {
      this.currentNumber = this.targetNumber || targetNumber;
      this.targetNumber = targetNumber;

      const difference = this.targetNumber - this.currentNumber

      Observable.interval(100)
        .take(difference)
        .subscribe(() => {
          this.currentNumber++;
        })
    }

    return this.currentNumber;
  }
}

Link source code tham khảo

Đến đây chắc các bạn cũng đã hiểu phần nào về Pipes trong angulalr 2 rồi đúng không nào ! Chào các bạn, hẹn gặp lại trong bài viết tiếp theo !

0