简体   繁体   English

组件初始化之前的Angular Load Async数据

[英]Angular Load Async data before component initialization

I have a problem to use data from API Calls: I want to use the retrieved data to set checked in a checkbox, but the component is initialized before the api response and I get some console error: 我在使用API​​调用中的数据时遇到问题:我想使用检索到的数据来设置复选框中的选中状态,但是在api响应之前初始化了该组件,并且出现了一些控制台错误:

ERROR TypeError: Cannot read property 'id' of undefined 错误TypeError:无法读取未定义的属性“ id”

I test the behaviour with a resolver too, but I have the same problem, even if the response array is logged before initialization: 我也使用解析器测试了行为,但是即使初始化之前记录了响应数组,我也遇到了同样的问题:

component.ts component.ts

...
export class RolesComponent implements OnInit {

  flag: boolean = false;
  simpleArr: object[] = [
    { userId: 1, id: 2 },
    { userId: 1, id: 3 },
    { userId: 1, id: 5 },
    { userId: 1, id: 7 }
  ]
  permArr: object[] = [];
  permArrResolved: object[] = [];

  levels = [
    { name: 0, description: 'Creazione nuovo utente' },
    { name: 1, description: 'Reset password di qualsiasi utente' },
    { name: 2, description: 'Eliminazione di qualsiasi utente' },
    { name: 3, description: 'Modifica livello di qualsiasi utente' },
    { name: 4, description: 'Rinnovo delle licenze' },
    { name: 5, description: 'Gestione completa delle licenze' },
    { name: 6, description: 'Gestione completa dei clienti' },
    { name: 7, description: 'Gestione completa dei PC' }
  ];

  constructor(private api: RolesApiService, private route: ActivatedRoute, ) {

    this.api.getKeys().subscribe(keys => {
      this.permArr = keys;
      console.log(this.permArr);
      this.flag = true
    });

    this.route.data.pipe(
      map(data => data.cres)).subscribe((key) => {
        this.permArrResolved = key;
        console.log(this.permArrResolved);
      });

  }

  ngOnInit() {
    console.log('component is initialized');
  }

}

component.html component.html

<form *ngIf="flag">
  <h2>with permArr[0].id</h2>
  <ng-container *ngFor="let level of levels">
    <input type="checkbox" [checked]="level.name === permArr[0]?.id" />{{level.name}} - {{level.description}}
    <br>
  </ng-container>

<hr>

<h2>with simpleArr[level.name].id</h2>
  <ng-container *ngFor="let level of levels">
    <input type="checkbox" [checked]="level.name === simpleArr[level.name]?.id" />{{level.name}} - {{level.description}}
    <br>
  </ng-container>

<hr>

  <h2>with permArr[level.name].id</h2>
  <ng-container *ngFor="let level of levels">
    <input type="checkbox" [checked]="level.name == permArr[level.name]?.id" />{{level.name}} - {{level.description}}
    <br>
  </ng-container>

<hr>

  <h2>with permArr[level.name].id using resolver</h2>
  <ng-container *ngFor="let level of levels">
    <input type="checkbox" [checked]="level.name == permArrResolved[level.name]?.id" />{{level.name}} - {{level.description}}
    <br>
  </ng-container>

</form>

I've made a stackblitz demo to show the error, the api-service, the routing and the resolver I use. 我制作了一个stackblitz演示来显示错误,api服务,路由和我使用的解析器。 is here: https://stackblitz.com/edit/async-angular-resolver 在这里: https : //stackblitz.com/edit/async-angular-resolver

How can I solve this problem? 我怎么解决这个问题?

EDIT: using safe oprators do not solve the bug EDIT2: using *ngIf in form tag do not solve the bug 编辑:使用安全的操作者不能解决该错误编辑2:在表单标记中使用* ngIf不能解决该错误

There are already several answers here that correctly answer the question you are asking - the reason they dont work for you is because the data you are binding does not matching your ids. 这里已经有几个答案可以正确回答您要问的问题-它们对您不起作用的原因是因为您绑定的数据与您的ID不匹配。

Your previous questions were both basically asking the same thing: 您先前的问题基本上都是在问同一件事:

To prevent further wasted effort from the community, I've gone to the effort of writing the debug code you should be writing yourself. 为了避免社区进一步浪费精力,我已经花了很多精力编写自己应该编写的调试代码。 This shows how the safe navigation operator fixes the template issue , as several people have suggested already - wrapping with *ngIf would also solve the problem and the values I've added show why your tick boxes are not checked. 正如一些人已经建议的那样,这显示了安全导航操作员是如何解决模板问题的 -用*ngIf包裹也可以解决此问题,并且我添加的值说明了为什么未选中复选框。

https://stackblitz.com/edit/async-angular-resolver-hxxyw4?file=src/app/roles/roles.component.html https://stackblitz.com/edit/async-angular-resolver-hxxyw4?file=src/app/roles/roles.component.html

You can use the safe navigation operator : ?. 您可以使用安全的导航操作符?.

The Angular safe navigation operator (?.) is a fluent and convenient way to guard against null and undefined values in property paths. Angular安全导航运算符(?。)是防止属性路径中的空值和未定义值的一种流畅便捷的方法。

For example: 例如:

[checked]="level.name === permArr[0]?.id"

This is essentially equivalent to permArr[0] && permArr[0].id 这本质上等效于permArr[0] && permArr[0].id

Load View after response using *ngIf : 使用*ngIf响应后加载视图:

<form *ngIf="flagpermArr && flagpermpermArrResolved">
    <h2>with permArr[0].id</h2>

    <ng-container *ngFor="let level of levels">
        <input type="checkbox" [checked]="level.name === permArr[0]?.id" />{{level.name}} - {{level.description}}
        <br>
    </ng-container>
    <hr>
    <h2>with simpleArr[level.name].id</h2>

    <ng-container *ngFor="let level of levels ; let i = index">

 <!-- <input *ngIf="" type="checkbox" [checked]="level.name === simpleArr[level.name].id" />{{level.name}} - {{level.description}} 
    -->
        <br>
    </ng-container> 
    <hr>
    <h2>with permArr[level.name].id</h2>
    <ng-container *ngFor="let level of levels">
        <input type="checkbox" [checked]="level.name == permArr[level.name]?.id" />{{level.name}} - {{level.description}}
        <br>
    </ng-container>
    <hr>
    <h2>with permArr[level.name].id using resolver</h2>
    <ng-container *ngFor="let level of levels">
        <input type="checkbox" [checked]="level.name == permArrResolved[level.name]?.id" />{{level.name}} - {{level.description}}
        <br>
    </ng-container>
</form>

TS: TS:

 export class RolesComponent implements OnInit {

  flagpermArr: boolean = false;
  flagpermpermArrResolved: boolean = false;

  simpleArr: object[] = [
    { userId: 1, id: 1 },
    { userId: 1, id: 2 },
    { userId: 1, id: 5 },
    { userId: 1, id: 7 }
  ]
  permArr: object[] = [];
  permArrResolved: object[] = [];

  levels = [
    { name: 0, description: 'Creazione nuovo utente' },
    { name: 1, description: 'Reset password di qualsiasi utente' },
    { name: 2, description: 'Eliminazione di qualsiasi utente' },
    { name: 3, description: 'Modifica livello di qualsiasi utente' },
    { name: 4, description: 'Rinnovo delle licenze' },
    { name: 5, description: 'Gestione completa delle licenze' },
    { name: 6, description: 'Gestione completa dei clienti' },
    { name: 7, description: 'Gestione completa dei PC' }
  ];

  constructor(private api: RolesApiService, private route: ActivatedRoute, ) {
  }

  ngOnInit() {
    this.api.getKeys().subscribe(keys => {
      this.permArr = keys;
      this.flagpermArr = true
    });

    this.route.data.pipe(
      map(data => data.cres)).subscribe((key) => {
        this.permArrResolved = key;
        this.flagpermpermArrResolved = true
      });
  }

You could use: 您可以使用:

<ng-container *ngIf="permArr && permArrResolved"> your code here </ng-container>

The containers content will only be rendered when permArr and perArrResoved have data in them. 仅当permArr和perArrResoved中包含数据时,才会显示容器的内容。

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

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