Skip to main content

ngIf

ngIf הוא directive מבני. מה שאומר שהוא משנה את ה-DOM על ידי הוספה או הסרה של אלמנטים ממנו. ngIf מוסיף או מוריד אלמנטים על פי תנאי מסויים. הוא יהיה מחובר לביטוי שיגיע מתוך ה-ts שיחזיר true או false.

אם הערך שחזר הוא true, האלמנט יתווסף לעמוד, אם הערך שחזר הוא false האלמנט יוסר.

בדוגמא נראה שכל ה-container המסויים הזה יוצג רק אם הערך של userLoggedIn יהיה true. אחרת הוא וכל התכולה שלו לא יוצגו.

component.html
<div class="container" *ngIf="userLoggedIn">

.... visible only to authenticated users

<button *ngIf="user.admin">Delete User</button>

</div>

שימוש ב-ng-container

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

כשמוסיפים ng-container לא נוסף לנו רכיב ב-DOM ולכן נוח להשתמש בו לעטוף קטעי קוד יחד.

component.html
<ng-container *ngIf="userLoggedIn">

.... visible only to authenticated users

</ng-container>

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

נניח שיש לי for שאני רוצה שיעבוד רק בתנאי מסויים. אני יכולה ליצור ng-container חיצוני עם התנאי של if ובתוכו לשים את לולאת ה-for.

if-else

אם יש לנו if נרצה גם את האפשרות להתייחס ל-else. כאן נצטרך לבנות את קטע הקוד שיחליץ את הקוד שלא יבוצע ולקרוא לו.

component.html
<div class="container" *ngIf="courses.length; else noCourses">
<h1>All Courses</h1>
....
</div>

<ng-template #noCourses>
<h1>No courses available.</h1>
</ng-template>

if-then-else

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

component.html
<ng-container *ngIf="courses.length; then coursesList; else noCourses">
</ng-container>

<ng-template #coursesList>
<h1>All courses available</h1>
....
</ng-template>

<ng-template #noCourses>
<h1>No courses available.</h1>
</ng-template>

ngIf ו-observable

אם יש לנו מידע בתוך observable ואנחנו רוצים להשתמש בו בתוך ngIf נעשה את זה בצורה הזאת:

component.html
<ng-container *ngIf="(courses$ | async) as courses">
<div class="courses">
{{courses.length}}
</div>
</ng-container>

נשתמש ב-pipe של async ונגדיר את המשתנה בצורה מקומית על ידי המילה as. בצורה הזאת ההערכה של המשתנה תעשה רק אחרי שהוא נשלף ומאוכלס.

ה-pipe של async יגרום ל-subscribe של ה-observable והערכים יהיו זמינים בטמפלט.

פעולת ה-unsubscribing תעשה אוטומטית עם סיום חיי הרכיב.

היתרון הוא שהרכיב ישתנה אוטומטית אם יהיה שינוי בערך של משתנה ה-observable.

שימוש יתר ב-observable עם ngIf

בעיה יכולה להיווצר כאשר יש קומפוננטות מורכבות שיש בהם שימוש בכמה ערכים של observable עם כמה pipe של async שנקראים במקומות שונים של הקוד כמו בדוגמא.

הקוד יראה משהו כזה:

component.html
<div class="header" *ngIf="(user$ | async) as user">

... this section of the page only needs the user ...

<button *ngIf="!user">Login</button>
<button *ngIf="user.loggedIn">Logout</button>
</div>

<div class="body" *ngIf="(courses$ | async) as courses">
<ng-container *ngIf="(lessons$ | async) as lessons">

... we also need the user here again ...
<ng-container *ngIf="(user$ | async) as user">
... this section of the page needs courses, lessons, and the user ....
</ng-container>
</ng-container>
</div>

<div class="footer" *ngIf="(courses$ | async) as courses">
<ng-container *ngIf="(lessons$ | async) as lessons">
... this section of the page only needs the courses and the lessons ...
</ng-container>
</div>

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

component.html
<ng-container *ngIf="(user$ | async) as user">
<ng-container *ngIf="(courses$ | async) as courses">
<ng-container *ngIf="(lessons$ | async) as lessons">

<div class="header">
...
</div>

<div class="body">
...
</div>

<div class="footer">
...
</div>

</ng-container>
</ng-container>
</ng-container>

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

פתרון יכול להיות על ידי יצירת אובייקט observable אחד שיחזיר את כל המידע.

component.html
<ng-container *ngIf="(data$ | async) as data">
<div class="header">
... access the user via data.user ...
</div>
<div class="body">
... access the data via data.user, data.courses, data.lessons ...
</div>
<div class="footer">
... access the data via data.courses and data.lessons ...
</div>
</ng-container>

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

אם אתם רוצים להרחיב מוזמנים לקרוא במאמר הזה