I am learning Angular 2 and trying to follow their tutorial. Here is the code of the service that returns "Promise" of a mock object Folder.
import {Injectable, OnInit} from "@angular/core";
import {FOLDER} from "./mock-folder";
import {Folder} from "./folder";
@Injectable()
export class FolderService {
getFolder():Promise<Folder>{
return Promise.resolve(FOLDER);
}
}
It is declared in providers of my FolderModule
import {NgModule} from "@angular/core";
import {CommonModule} from "@angular/common";
import {FolderComponent} from "./folder.component";
import {MaterialModule} from "@angular/material";
import {FolderService} from "./folder.service";
@NgModule({
imports:[CommonModule, MaterialModule.forRoot()],
exports:[FolderComponent],
declarations:[FolderComponent],
providers:[FolderService]
})
export class FolderModule{
}
Folder component should import FolderService and use it to obtain the Folder object.
import {Component, OnInit} from "@angular/core";
import {Folder} from "./folder";
import {FolderService} from "./folder.service";
@Component({
selector: 'folder',
moduleId: module.id,
templateUrl: "./folder.component.html"
})
export class FolderComponent implements OnInit {
folder:Folder;
constructor(private folderService:FolderService) {
}
ngOnInit():void {
this.getFolder();
}
getFolder() {
this.folderService.getFolder().then((folder) => this.folder = folder);
}
}
And yes, i do import my FolderModule in the root module
@NgModule({
imports: [BrowserModule, CommonModule, MaterialModule.forRoot(), FolderModule, AppRoutingModule],
providers:[],
declarations: [AppComponent, LifeMapComponent, MyPageNotFoundComponent],
bootstrap: [AppComponent]
})
export class AppModule {
}
Here is the folder component template
<md-grid-list cols="3" [style.background] ="'lightblue'" gutterSize="5px">
<md-grid-tile *ngFor="let card of folder.cards">{{card.title}}</md-grid-tile>
</md-grid-list>
And here is the error i get in the console
EXCEPTION: Uncaught (in promise): Error: Error in http://localhost:3000/app/folders/folder.component.html:1:16 caused by: Cannot read property 'cards' of undefined TypeError: Cannot read property 'cards' of undefined
export class Folder {
public id:number;
public title:string;
public cards:Card[];
}
export class Card{
id :number;
title:string;
}
Voland,
This can be solved by using the "Elvis" operator on the collection being iterated over.
<md-grid-tile *ngFor="let card of folder.cards">{{card.title}}</md-grid-tile>
Should instead be:
<md-grid-tile *ngFor="let card of folder?.cards">{{card?.title}}</md-grid-tile>
Note the "?" after folder -- this will coerce the whole path to 'null', so it won't iterate. The issue is with the accessor on a null object.
You could also declare folder to an empty array [] to prevent this.
EDIT: To any onlookers, note that the Elvis operator is not available in your Typescript code, as it's not supported by the language. I believe that Angular 2 supports it though, so it is available in your views (really useful for AJAX requests, where your data has not arrived at the point of component instantiation!)
Use *ngIf
directive:
<md-grid-list *ngIf="folder" cols="3" [style.background] ="'lightblue'" gutterSize="5px">
<md-grid-tile *ngFor="let card of folder.cards">{{card.title}}</md-grid-tile>
</md-grid-list>
Angular tries to render the html before the promise is resolved, therefore folder
is undefined
and the exception is thrown.
With *ngIf="folder"
you tell Angular that it should ignore child elements if the expression is falsy.
<md-grid-tile *ngFor="let card of folder.cards">{{card.title}}</md-grid-tile>
will be added to the DOM if folder
is not undefined
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With