使用硬编码对象数组时,Angular Material的mat-button似乎无法在* NgFor内部使用

时间:2019-08-19 04:53:49

标签: javascript angular typescript angular-material

我在Angular工作了几年,遇到了一些奇怪的事情。我不确定这是否是该版本的怪异的Angular问题,或者我只是从未遇到过此特定问题。为了我自己的理智,我还在新的Angular应用程序中尝试了此操作,问题似乎仍然存在。

基本上,我创建了一个吸气剂来返回对象的硬编码数组。然后,我遍历模板中的对象以显示其数据并为每个项目创建一个按钮。现在,当我不使用 MatButtonModule mat-button时,该按钮将按预期工作。但是,当我使用mat-button时,按钮将不再触发。

在某些情况下,我可以让mat-button工作。如果我不使用吸气剂,而是在模板中调用locationsTest,则按钮将起作用。如果我返回变量locationsTest,getter也将起作用。另外,如果我从吸气剂中返回一个字符串数组或一个整数数组,则mat-button将起作用,并且单击时按钮将触发。似乎只有当吸气剂返回硬编码的对象数组时,这种情况才会发生。

所以我的问题是,有人知道为什么会这样吗?以下是失败的用例,我不确定为什么会发生这种情况。在进行以下测试时,请确保在安装@ angular / material软件包后导入 MatButtonModule ,否则mat-button不会执行任何操作。

component.html

<div *ngFor="let location of locations">
  <div>
    <h4>{{ location.name }}</h4>
    <p>{{ location.address }}</p>
    <p>{{ location.city }} </p>
  </div>
</div>

<button mat-button (click)="GoToLocation()">
  Go To Location
</button>

component.ts

let locationsTest = [
    {
      name: "Walmart",
      address: "123 Mcdougal Street W",
      city: "Toronto"
    },
    {
     name: "Barber Shop",
     address: "22 cat Street",
     city: "Toronto"
   }
 ];

public get locations(): any {
  return [
    {
      name: "Walmart",
      address: "123 Mcdougal Street W",
      city: "Toronto"
    },
    {
     name: "Barber Shop",
     address: "22 cat Street",
     city: "Toronto"
   }
 ];
}

public GoToLocation(): void {
  console.log('Going to Location');
}

感谢您的见解。

1 个答案:

答案 0 :(得分:0)

此问题可能是由多种不同原因引起的。我建议尝试以下内容作为检查清单,因为这些总是最终成为我的原因:

  1. 是否安装了角材料?

    我发现有时我们忘记安装Angular材质,并且由于尚未发现的其他错误而将错误隐藏了。

  2. 是否导入了模块?在这种情况下,MatbuttonModule

    这是我遇到的另一个常见问题,我们忘记了导入模块,因此Angular不知道组件或指令是什么。在这种情况下,Angular可能不知道mat-button指令是什么,但是由于存在另一个错误,该错误是静默的。

  3. (最常见),您使用的是一种吸气剂,其返回的值会自动更新!

    这是我最常遇到的问题,但无法解决。当我们开发返回模拟数据时,这是很常见的。但是,如果要在getter中创建Observable或BehaviorSubject或设置一个一般值,则可能导致Angular继续触发生命周期方法。依次,这将阻止触发角度功能,因为Angular忙于不断更新。

    示例:

    //TS File: 
    public get userNames(): Observable<Array<string>> {
      public names = new BehaviorSubject<Array<any>>(null);
    
      let mockNames = [
        'L1ghtk3ira',
        'Thor4Life',
        'OverwatchKing'
      ];
    
      names.next(mockNames)
    
      return names.asObservable();
    }
    
    /html file
    <ng-container *ngIf="userNames | async as listOfUserNames;'>
      <p *ngFor="let userName of listOfUserNames">
        {{ userName  }}
      </p>
    </ng-container>
    

    上面的代码似乎无害,但是当我们在模板中使用它时,实际上是在发生什么。当我们的*ngIf(或者即使我们直接进行*ngFor循环异步)时,角度会获取数据并在此期间设置新数据。 Angular会检测到此情况,并决定在当前更改检测完成后执行另一次更改检测。当下一次更改检测发生时,此问题会重复出现。因此,即使您在屏幕上看不到任何变化,因为数据相同,它仍会形成不断变化的变化检测循环。因此,由于Angular会不断检查和更新自身,因此诸如(click)事件之类的for循环中的任何内容都无法触发。

    有两种方法可以解决此问题。拳头很简单,我们可以以任何方式在getter外部设置值,在我的示例中,我选择将其设置为初始值。将过去的TS文件更改为以下内容:

    public names = new BehaviorSubject<Array<any>>(
      [
        'L1ghtk3ira',
        'Thor4Life',
        'OverwatchKing'
      ]
    );
    
    public get userNames(): Observable<Array<string>> {
      return names.asObservable();
    }
    

使用Angular时要记住的一个好的经验法则是,如果您在模板中使用吸气剂,请不要在吸气剂内设置值,因为它将触发无尽的变化检测之海。尽管应该不言而喻,但还是会发生错误。