简体   繁体   English

Angular 2组件DOM在OnInit方法中解析bean之前绑定到组件中的属性

[英]Angular 2 component DOM binds to the property in component before it has bean resolved in OnInit method

I am learning Angular 2 and trying to follow their tutorial. 我正在学习Angular 2并尝试按照他们的教程。 Here is the code of the service that returns "Promise" of a mock object Folder. 这是返回模拟对象Folder的“Promise”的服务代码。

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 它在我的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. 文件夹组件应导入FolderService并使用它来获取Folder对象。

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 是的,我在根模块中导入我的FolderModule

@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 EXCEPTION:未捕获(在承诺中):错误: http:// localhost:3000 / app / folders / folder.component.html:1:16引起的错误:无法读取未定义的属性' cards'TypeError:无法读取属性'卡片的未定义

export class Folder {
  public id:number;
  public title:string;
  public cards:Card[];
}

export class Card{
  id :number;
  title:string;
}

Voland, Voland,

This can be solved by using the "Elvis" operator on the collection being iterated over. 这可以通过在迭代的集合上使用“Elvis”运算符来解决。

<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. 在文件夹之后 - 这将强制整个路径为'null',因此它不会迭代。 The issue is with the accessor on a null object. 问题在于null对象上的访问器。

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. 编辑:对于任何旁观者,请注意您的Typescript代码中没有Elvis运算符,因为该语言不支持。 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!) 我相信Angular 2支持它,所以它在你的视图中可用(对于AJAX请求非常有用,你的数据还没有到达组件实例化点!)

Use *ngIf directive: 使用*ngIf指令:

<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. Angular尝试在解析promise之前呈现html,因此undefined folder并抛出异常。
With *ngIf="folder" you tell Angular that it should ignore child elements if the expression is falsy. 使用*ngIf="folder"您告诉Angular如果表达式是假的,它应该忽略子元素。

<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 . 如果folder undefined <md-grid-tile *ngFor="let card of folder.cards">{{card.title}}</md-grid-tile>将被添加到DOM中。

Your error is in the classes: 您的错误在课程中:

export class Folder {
  public id:number;
  public title:string;
  public cards:Card[];
}

export class Card{
  id :number;
  title:string;
}

You have forgotten the constructor: 你忘记了构造函数:

export class Folder {
  constructor( 
     public id:number,
     public title:string,
     public cards:Card[])
  {}
}

export class Card{
  constructor( 
    public id :number,
    public title:string)
  { }
}

And probably as previously suggested use the elvis operator or ngIf. 并且可能如先前建议的那样使用elvis运算符或ngIf。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM