sandrooco
sandrooco

Reputation: 8716

Angular2 Templating: Safe Navigation Operator and *ngIf

My goal is to hide an element when no items are available. My template so far:

<div *ngIf="(projects | async)?.userProjects.length !== 0">
    <div class="sortWrapper">
        <h3>Your projects</h3>
    </div>

    <div class="listElementWrapper">
        <div class="listElement" *ngFor="let userProject of (projects| async)?.userProjects" (click)="redirectToProject(project)">
            <h4>{{ userProject.ProjectName }}</h4>
        </div>
    </div>
</div>

The *ngFor with the safe navigation operator works as expected. The first line (*ngIf) doesn't though. As the userProjects property is async, the length somehow doesn't update. Did I miss a key concept here?

Component: private projects: Observable<any[]>;

Upvotes: 0

Views: 1993

Answers (2)

Poul Kruijt
Poul Kruijt

Reputation: 71901

I believe you would like it to be !== 0. Then it will actually show when it has results :)

<div *ngIf="(projects | async)?.userProjects.length !== 0">

Apparently this is an issue in angular. Check here for more information:

https://github.com/angular/angular/issues/9641

The solution could be to not use the async pipe and set a variable userProjects inside your component:

untested code ahead

<div *ngIf="userProjects.length > 0">
    <div class="sortWrapper">
        <h3>Your projects</h3>
    </div>

    <div class="listElementWrapper">
        <div class="listElement" *ngFor="let userProject of userProjects" (click)="redirectToProject(project)">
            <h4>{{ userProject.ProjectName }}</h4>
        </div>
    </div>
</div>

And the component something like this:

export class UserProjectsComponent {

   public userProjects: UserProject[] = [];

   public projectSub: Subscription;

   constructor(public projectService: ProjectService){}

   ngOnInit() {
      this.projectSub = this.projectService.getUserProjects().subscribe((userProjects) => {
          this.userProjects = userProjects
      });
   }

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

You can however also define the userProjects on your projectService:

@Injectable()
export class ProjectService {

  public get userProjects(): UserProject[] {
     return this._userProjects;
  }  

  private _userProjects: UserProject[] = [];

  constructor(private http: Http){}

  public getUserProjects(): void {
     this.http.get().map(resp => resp.json()).subscribe((userProjects) => {
          this._userProjects = userProjects;
     });
  }
}

and then you can keep the template as I defined above here, but change your component to the simpler:

export class UserProjectsComponent {

   public get userProjects(): UserProject[] {
      return this.projectService.userProjects;
   }

   constructor(public projectService: ProjectService){}

   ngOnInit() {
      this.projectService.getUserProjects();
   }
}

Upvotes: 0

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

Reputation: 657238

Add ? before length as well

<div *ngIf="(projects | async)?.userProjects?.length == 0">

Upvotes: 0

Related Questions