【问题标题】:Angular *ngIf Condition inside *ngFor to show hide items*ngFor 内的 Angular *ngIf 条件以显示隐藏项目
【发布时间】:2021-07-19 13:28:43
【问题描述】:

我正在使用 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>

我正在调用这个方法 show hide my li

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

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

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

【问题讨论】:

  • 你有多少个菜单项?
  • 我有 8 个菜单项
  • 这能回答你的问题吗:stackoverflow.com/questions/43081810/…
  • 您对 IsAllowed() 方法有什么期望。您可以分享该方法的实际代码吗?
  • 我想添加一些条件,比如如果它是管理员返回 true 否则为 false

标签: angular typescript ngfor angular-ng-if


【解决方案1】:

As Abhishek Priyadarshi already wrote ...

问题是角度的变化检测。它会一次又一次地调用你的方法,...检查值是否改变。
解决它的一种方法是更改​​更改检测。 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);
  }
}

【讨论】:

  • 非常感谢。像冠军一样工作,使其更易于管理。
【解决方案2】:

您应该将其重写为管道。管道在值更改时执行,函数在每次运行更改检测时执行。更多细节可以在这个Stackoverflow question and answers.找到

【讨论】:

  • 在我的情况下我该怎么做,我需要在 IsAllowed() 方法中添加一些条件。
【解决方案3】:

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

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>

【讨论】:

  • 我添加了更多信息来提问。
  • 因此函数与 menuItem 无关,因此您可以在 .ts 中创建两个单独的变量,例如 isAdmin 和 isUser,并使用组件中的函数为它们返回 true/false。
【解决方案4】:

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

在为 ngForOf 指令触发的每个 ngDoCheck 中,Angular 都会检查哪些对象发生了变化。它在这个过程中使用了差异,每个差异都使用 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 的工作原理感到好奇,请阅读answer

【讨论】:

    【解决方案5】:

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

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

    【讨论】:

    • 你能告诉我IsAllowed()方法的逻辑吗?
    【解决方案6】:

    如果我理解您的问题,这应该可以。它检查用户角色,直到找到允许的角色。如果没有找到,则返回 false。

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

    【讨论】:

    • 它已经可以正常工作了,但即使我返回 false 硬编码,循环也永远不会停止。
    猜你喜欢
    • 1970-01-01
    • 2017-11-07
    • 2016-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-18
    • 2018-06-04
    • 1970-01-01
    相关资源
    最近更新 更多