Pipe מותאם

מעבר לשימוש ב-pipe שקיימים באנגולר יש אפשרות לבנות pipe מותאמים אישית לצרכי הפיתוח של האפליקציה.

נניח שיש לנו מידע שאנחנו רוצים להציג בדרך מסויימת, אבל לא לשנות את הערך שיש לנו בתוך המשתנה. למשל, לקחת מרחק שמכניסים במיילים ולהפוך אותו לקילומטרים.

קובץ app.component.ts

miles: number;

onMilesChange(event: Event) {
  this.miles = Number((event.target as HTMLInputElement).value);
}

נכניס את המשתנה לתצוגה.

קובץ app.component.html

<div class="row align-items-end">
    <div class="col-md-3">
      <label class="form-label">Miles</label>
      <input (input)="onMilesChange($event)" class="form-control" />
    </div>

    <div class="col-md-3">
      <h4>{{ miles }} km</h4>
    </div>
  </div>

יצירת ה-pipe

כדי ליצור pipe משתמשים בשורת הפקודה. כדי לשמור על הסדר אני מייצרת תיקייה שבתוכה יהיו כל ה-pipes.

ng g p pipes/convert-dis

כך נראה הקובץ שנוצר – convert-dis.pipe.ts

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'convertDis'
})
export class ConvertDisPipe implements PipeTransform {
  transform(value: unknown, ...args: unknown[]): unknown {
    return null;
  }
}

יש לנו פונקציה אחת שמופעלת בכל פעם שקוראים ל-pipe. הפונקציה מקבלת את הערך שעליו הפעלנו את ה-pipe, עושה חישובים, ומחזירה לנו את הערך המעובד.

נרצה גם לטפל במקרים שהמשתמש הכניס ערך לא מתאים, למשל מחרוזת ל-pipe שאמור לטפל במספרים.

בדוגמא אנחנו רוצים לקבל מיילים ולהחזיר קילומטרים, אז ההמרה תהיה הקלט * 1.6.

קובץ convert-dis.pipe.ts

export class ConvertDisPipe implements PipeTransform {

  transform(value: unknown, ...args: unknown[]): unknown {
    if(!value)
      return '';

    return Number(value) * 1.6;
  }
  
}

קובץ app.component.html

<h4>{{ miles | convertDis }} km</h4>

ככה תראה התוצאה:

המספר הזה הוא לא מה שאני בדיוק רוצה, הוא ארוך מידי, ולכם אני רוצה להפעיל עליו את ה-pipe שמעצב את המספרים. אם תנסו לעשות את זה תקבלו שגיאה.

למה? כי ה-pipe לא מחזיר כרגע משתנה מסוג כלשהו, וה-pipe שמעצב מספרים מצפה לקבל רק מספר. לכל ביצתי שינוי קטן כדי לאפשר את המשימה, הגדרתי את הערך שחוזר מה-pipe כ-number.

קובץ convert-dis.pipe.ts

transform(value: unknown, ...args: unknown[]): number {
    if(!value)
      return null;

    return Number(value) * 1.6;
}

עכשיו אפשר לשרשר את ה-pipes.

קובץ app.component.html

<h4>{{ miles | convertDis | number: '1.0-2' }} km</h4>/

הוספת אפשרויות ל-pipe

כרגע השימוש ב-pipe הוא להמרה ממיילים לק"מ בלבד. אבל מה אם אני רוצה לבנות pipe כללי יותר, שיקבל מרחק וימיר אותו ליחידות שאני רוצה?

המטרה שלי היא שיהיה אפשר להוסיף 'm' או 'km' על מנת לסמן מה ההמרה שאני רוצה.

מי שמקבל את הארגומנטים האלה ב-pipe הוא המשתנה args שבכותרת הפונקציה. נשנה את ההגדרה כך שתקבל משתנה אחד:

קובץ convert-dis.pipe.ts

transform(value: unknown, targetUnits: string): number {
    if(!value)
      return null;

    return Number(value) * 1.6;
}

הצעד הבא יהיה לטפל בארגומנט שהתקבל.

transform(value: unknown, targetUnits: string): number {
    if(!value)
      return null;

    switch(targetUnits){
      case 'km':
        return Number(value) * 1.6;
      case 'm':
        return Number(value) / 1.6;
      default:
        return Number(value)
        // throw new Error('Target unit not supported');
    }
  }

לי כרגע לא מתאים לזרוק שגיאה, כי זה יצור לי בעיה עם שרשור ה-pipes אבל שמתי בהערה אפשרות של זריקת שגיאה במקרה שמכניסים ערך לא רלוונטי.

קובץ app.component.html

<div class="row align-items-end">
  <div class="col-md-3">
    <label class="form-label">Miles</label>
    <input (input)="onMilesChange($event)" class="form-control" />
  </div>
  <div class="col-md-5">
    <h4>{{ miles | convertDis: 'km' | number: '1.0-2' }} km</h4>
  </div>
</div>

<div class="row align-items-end">
  <div class="col-md-3">
    <label class="form-label">Kilometers</label>
    <input (input)="onKmChange($event)" class="form-control" />
  </div>
  <div class="col-md-5">
    <h4>{{ km | convertDis: 'm' | number: '1.0-2' }} miles</h4>
  </div>
</div>

ניווט במאמר

מאמרים אחרונים

Weekly Tutorial