在 ngOnInit() 中使用数据绑定从本地 JSON 文件读取数据会导致未定义的变量

Posted

技术标签:

【中文标题】在 ngOnInit() 中使用数据绑定从本地 JSON 文件读取数据会导致未定义的变量【英文标题】:Read data from a local JSON file with data binding in ngOnInit() results in undefined variable 【发布时间】:2018-05-19 10:59:12 【问题描述】:

我正在尝试从 assets 文件夹中的 json 文件中获取数据,然后将此数据分配给一个变量,该变量将绑定到子组件的另一个 @Input 变量。

代码

基于网上的多种解决方案,我这样检索我的JSON数据:

@Injectable()
export class JSONService 

    constructor(private http: HttpClient)  

    public fromJSON(jsonFileName: string): Observable<any[]> 
      let result: any[] = new Array();
      let pathToJson: string = "assets/" + jsonFileName + ".json";

      return this.http.get(pathToJson).map(data => 
        let result: any[] = new Array();
        // Apply some treatment on data and push it to the result array
        return result;
      );
    

然后我在父组件的ngOnInit() 方法中调用我的服务:

ngOnInit() 
    this.jsonService.fromJSON("users.json").subscribe(fields => 
      this.fields= fields;
      console.log(this.fields); // Log (I): this.fields is well defined
    );
    console.log(this.fields); // Log (II): this.fields is undefined

变量fields绑定到子组件的地方:

<child-component [childFields] = "fields"></child-component>
问题

我面临的问题是对fromJSON 方法的异步调用导致this.fields 在页面执行生命周期的某个时刻未定义(上面代码中的Log (II)),这导致将this.fields 变量的未定义值发送到子组件。

如何避免 fields 变量的值未定义,并确保子组件始终加载 json 文件中的数据?

【问题讨论】:

在你的路由中使用解析器,它会调用服务并在组件构造函数中接收响应 【参考方案1】:

只需添加 *ngIf 以检查数据是否加载

<child-component *ngIf="fields" [childFields] = "fields"></child-component>

【讨论】:

【参考方案2】:

假设你的组件有点像下面

export class SomeComponent implements OnInit 
  public fields: any[];

  ngOnInit() 
    this.jsonService.fromJSON("users.json").subscribe(fields => 
      this.fields = fields;
      console.log(this.fields); // Log (I): this.fields is well defined
    );
    console.log(this.fields); // Log (II): this.fields is undefined
  

然后您可以使用空数组初始化 fields

public fields: any[] = [];

模板中的或

<child-component *ngIf="fields" [childFields]="fields"></child-component>

【讨论】:

【参考方案3】:

服务.ts

@Injectable()
export class JSONService 

    constructor(private http: HttpClient)  

    public fromJSON(jsonFileName): Observable<any[]> 
      console.warn('Retriving Default Data from File.......');
    return this.http.get(filename)
      .map(this.extractData)
      .catch(this.handleError);
    
  private extractData(res: Response) 
    let body = res.json();
    return body || [];
  

  private handleError(error: any) 
        const errMsg = (error.message) ? error.message :
          error.status ? `$error.status - $error.statusText` : 'Server error';
        console.error(errMsg);
        console.log('Server Error!');
        return Observable.throw(errMsg);
      

parent.component.ts

constructor(public jsonService: jsonService) 
  

  ngOnInit() 

          this.jsonService.fromJSON('assets/users.json').subscribe(
          function (success) 
            this.data = success;
           this.datahandle(success);
          ,
          error => console.log('Getting Server Data Error :: ' + 
    JSON.stringify(error)));


datahandle(jsonData)

console.log('check data' + JSON.stringify(jsonData)); <-----check data

// may parse your jsonData  if required
this.fields = jsonData ;

let keys = Object.keys(jsonData);
console.log(keys);




parent.component.html

<child-component *ngIf="fields" [childFields] = "fields"></child-component>

【讨论】:

以上是关于在 ngOnInit() 中使用数据绑定从本地 JSON 文件读取数据会导致未定义的变量的主要内容,如果未能解决你的问题,请参考以下文章

Angular2,TypeScript,如何读取/绑定属性值到组件类(在 ngOnInit 中未定义)[重复]

如何从 ngOnInit Angular 中的服务获取数据

为啥每次都重复调用 ngOnInit

Angular 中 ngOnInit() 上的动态创建类字段

自学ng -生命周期钩子

如何停止在 ngOnInit() 之前调用的 ngOnChanges