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