ngFor הוא directive מובנה באנגולר. אנחנו משתמשים בו כדי לעבור בלולאה על משתנה איטרטיבי ובכל סיבוב של הלולאה אנחנו מוסיפים קוד html לעמוד.

ngFor הוא Structural directive, מה שאומר שהוא משנה את ה-DOM על ידי הוספה או הורדה של אלמנטים מהעמוד. כשאנחנו קוראים ל-Structural directive נשתמש ב-* לפני שם ה-directive.

דוגמא לשימוש ב-ngFor

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

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

products.component.ts

items: Item[];

ה-ngFor יעבור בלולאה על מערך ה-items ובעל מעבר הוא ישכפל את התוכן שנמצא בתוך האלמנט שמפעיל אותו.

products.component.html

<div *ngFor="let item of items">
    <h2>Name: {{ item.name }}</h2>
    <p>Price: {{ item.price }}</p>
</div>

כדאי לשים לב ש-item זמין רק בתוך הלולאה ולא מחוץ לה.

שימוש ב-index

אפשר לקבל בכל מעבר של הלולאה את ערך האינדקס של הלולאה.

products.component.html

<div *ngFor="let item of items; let i = index">
    <p>Product number {{ i }}</p>
    <h2>Name: {{ item.name }}</h2>
    <p>Price: {{ item.price }}</p>
</div>

עיצוב טבלה עם ngFor

שימוש נפוץ ב-ngFor הוא לבנות טבלה שמציגה מידע.

users.component.ts

users: User[];

users.component.html

<table>
    <tr>
        <th>Name</th>
        <th>Email</th>
    </tr>

    <tr *ngFor="let user of users">
        <td>{{ user.name }}</td>
        <td>{{ user.email }}</td>
    </tr>
</table>

נניח שאנחנו רוצים שהטבלה תהיה קריאה יותר ולכן רוצים לשנות את רקע השורות לסרוגין, ששורות זוגיות ואי זוגיות יהיו בצבעים שונים.

  1. ניתן ל-ngFor לסמן לנו את השורות הזוגיות והאי זוגיות.
  2. ניצור css שיתאים לעיצוב שורה זוגית ואי זוגית.
  3. נצמיד את העיצוב המתאים לכל שורה עם ngClass.

users.component.html

<table>
    <tr>
        <th>Name</th>
        <th>Email</th>
    </tr>

    <tr *ngFor="let user of users; let even = even; let odd = odd"
        [ngClass]="{ odd: odd, even: even }">
        <td>{{ user.name }}</td>
        <td>{{ user.email }}</td>
    </tr>
</table>

זיהוי האלמנט הראשון והאחרון

כמו זוגי ואי זוגי, ngFor יכול לזהות גם את הרכיב הראשון והאחרון ברשימה שלנו.

גם פה ניצור עיצוב מתאים ב-css בשם first ו-last והם יופעלו על האלמנט הראשון והאחרון ברשימה.

users.component.html

<table>
    <tr>
        <th>Name</th>
        <th>Email</th>
    </tr>

    <tr *ngFor="let user of users; let first = first; let last = last"
        [ngClass]="{ first: first, last: last }">
        <td>{{ user.name }}</td>
        <td>{{ user.email }}</td>
    </tr>
</table>

אופטימיזציה ל-ngFor

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

אבל מה אם יש לנו שינוי של שורה אחת בטבלה, ומה אם יש לנו טבלה עם המון נתונים ואנחנו לא רוצים שהיא כל פעם תטען מחדש, אלא רק השורות שבוצע בהן שינוי, הן אלא שיטענו שוב?

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

אנחנו מעבירים פונקציה ל-trackBy של הלולאה והיא מקבלת את האינדקס של ה-item ואת ה-item עצמו.

users.component.html

<table>
    <tr>
        <th>ID</th>
        <th>Name</th>
        <th>Email</th>
    </tr>

    <tr *ngFor="let user of users; trackBy: trackUser">
        <td>{{ user.id }}</td>
        <td>{{ user.name }}</td>
        <td>{{ user.email }}</td>
    </tr>
</table>

במקרה הזה בדיקת השינויים תעשה על פי שינוי ב-id של המשתמש.

users.component.ts

users: User[];

trackUser(index, user) {
    console.log(user);
    return user ? user.id : undefined;
}

בדרך כלל לא משתמשים ב-trackBy אלא אם יש בעיה של ביצועים ואז אפשר לראות איך זה יכול להועיל.

ngFor מקונן

אפשר להשתמש ב-ngFor בתוך אחד אחר.

users.component.html

<table>
    <tr>
        <th>Name</th>
        <th>Email</th>
        <th>Children</th>
    </tr>

    <tr *ngFor="let user of users">
        <td>{{ user.name }}</td>
        <td>{{ user.email }}</td>
        <td>
            <li *ngFor="let child of user.children">{{ child.name }}</li>
        </td>
    </tr>
</table>