Angular *ngIf 内的条件 *ngFor 显示隐藏项目

Angular *ngIf Condition inside *ngFor to show hide items

我正在使用 angular 12。这是 angular html 代码。

    <ul id="respMenu" class="horizontal-menu">
            <ng-container *ngFor="let menuItem of menuItems; let i = index">
                 <ng-container *ngIf="IsAllowed(['admin','user'])">
                 <li>
                     <a>
                         <span class="title">{{menuItem.title}}</span>
                     </a>
                 </li>
             </ng-container>
             </ng-container>
         </ul>

我正在调用此方法显示隐藏我的 li

  IsAllowed(allowedRoles){
    console.log("test");
    for (var i = 0; i < userRoles.length; i++) {
        if(allowedRoles.includes(userRoles[i])){
           return true;
        }
    }
  }

但它像数千次一样安慰测试文本。为什么会这样,请建议我更好的方法 it.I 有 8 个菜单项,它在 UI 中显示 8 个,但控制台多次。

IsAllowed 方法参数将动态加载,并且每个项目都不同。

您应该将其重写为管道。管道在值更改时执行,函数在每次更改检测为 运行 时执行。可以在 Whosebug question and answers.

中找到更多详细信息

您可以在组件中使用变更检测策略

@Component({
  // ...
  changeDetection: ChangeDetectionStrategy.OnPush
})

根据您的要求,您需要首先检查登录的用户是否为管理员,并在您的组件中检查:

get isAdmin(): boolean {
   if(this.user == 'admin') {
      return true;
   }
   return false;
}

然后在您的 HTML 组件中:

<ng-container *ngIf="isAdmin">
     <li>
         <a>
            <span class="title">{{menuItem.title}}</span>
         </a>
     </li>
</ng-container>

如果我理解你的问题,这应该可行。它会检查用户角色,直到找到允许的角色。如果 none 找到,returns 错误。

  IsAllowed(allowedRoles){
    userRoles.forEach(role => {
       if (allowedRoles.includes(role)) {
          return true
       }
    }
    return false
  }

您必须在 ngFor 循环中使用 TrackBy 函数。

在为 ngForOf 指令触发的每个 ngDoCheck 中,Angular 检查哪些对象已更改。它为此过程使用 differ,每个 diff 使用 trackBy 函数将当前对象与新对象进行比较。默认 trackBy 函数按身份跟踪项目:

const trackByIdentity = (index: number, item: any) => item;

trackBy*ngFor

中的例子
<ng-container *ngFor="let menuItem of menuItems; let i = index; trackBy:trackByIdentity;">

trackByIdentity 功能在您的控制器上的样子如何

trackByIdentity(menuItem) {
    return menuItem.title; // here, you can track by any field.
}

如果您对 ngFor 的幕后工作原理感到好奇,请阅读这篇文章

...

问题是 angular 的变化检测。它会一次又一次地调用您的方法,...以检查值是否已更改。
解决它的一种方法是更改​​更改检测。 ChangeDetectionStrategy.OnPush 是最佳选择,但这可能会破坏您的组件。请阅读 docs.

这就是我写一个新答案的原因:你应该写一个新的结构指令。因此,您可以在所有组件上使用该方法并拥有一个“标准”。看看 strucural directive docs.

下面是您的代码的想法:

HTML:

<ng-container *appAllowed="user,admin">
    <li>
        <a>
            <span class="title">{{menuItem.title}}</span>
        </a>
    </li>
</ng-container>

TS

@Directive({ selector: '[appAllowed]'})
export class AllowedDirective {

  constructor(private userService: UserService,
              private templateRef: TemplateRef<any>,
              private viewContainer: ViewContainerRef) { }

  @Input() set appAllowed(allowed: string) {
    var allowedList = allowed.split(',');

    for (let requiredRole of allowedList) {
       if (!this.userService.hasRole(required)) {
          this.viewContainer.clear();
          return;
       }
    }
    
    this.viewContainer.createEmbeddedView(this.templateRef);
  }
}

如果你不能使用ChangeDetectionStrategy.OnPush,那么你可以减少工作量,像这样:

@Directive({ selector: '[appAllowed]'})
export class AllowedDirective {

  private roles: string[];

  constructor(userService: UserService,
              private templateRef: TemplateRef<any>,
              private viewContainer: ViewContainerRef) {
      userService.me().subscribe(me => this.roles = me.roles);
  }

  @Input() set appAllowed(allowed: string) {
    var allowedList = allowed.split(',');

    for (let requiredRole of allowedList) {
       if (!this.roles.includes(requiredrole)) {
          this.viewContainer.clear();
          return;
       }
    }
    
    this.viewContainer.createEmbeddedView(this.templateRef);
  }
}