问题绑定管道异步客栈自定义指令输入

problem binding pipe async inn custom directive input

我有点大问题!

我有自定义指令,根据输入入口放置隐藏属性。

 import { Directive, ElementRef, Input, OnInit, Renderer2 } from '@angular/core';

@Directive({
  selector: '[ticketingPrimeCreateTicketButtonActive]'
})
export class CreateTicketButtonActiveDirective implements OnInit {
  @Input() ticketingPrimeCreateTicketButtonActive: string;

  constructor(private elRef: ElementRef, private renderer: Renderer2) {}

  ngOnInit() {
    console.log(this.ticketingPrimeCreateTicketButtonActive);
    if (!(this.ticketingPrimeCreateTicketButtonActive === 'Administrador' || this.ticketingPrimeCreateTicketButtonActive === 'Comercial')) {
      this.renderer.setAttribute(this.elRef.nativeElement, 'hidden', 'true');
    }
  }
}

这个指令如果有效,因为当我对入口进行硬编码时,它可以正常工作,如下所示:

<button [ticketingPrimeCreateTicketButtonActive]="'Administrador'"  class="col-1 add"  [ngClass]="{ addInSmall: isSmallOrXSmall() }" (click)="addTicket()">
            <span class="material-icons add-icon"> add_to_photos </span>
          </button>

然后问题是我必须从数据库中获取该字符串。

我试图创建一个 observable 并使用管道异步,但它总是采用 null。显着的组件代码:

export class TicketingKanbanComponent implements OnInit, OnDestroy, AfterViewInit {
  public activeUserRoleNameSubject: BehaviorSubject<string>;
  public activeUserRoleName$: Observable<string>;

....
}

    async ngOnInit(): Promise<void> {
        const roleUid = (await 
        this.userBaseGesRoleRepository.findOneByActiveUser().toPromise()).metadata.roleUid;
        this.role = (await this.roleRespository.findOne(roleUid).toPromise()).metadata.name;
        this.activeUserRoleNameSubject = new BehaviorSubject<string>(this.role)
        this.activeUserRoleName$ = this.getActiveUserRoleName$();


        ....
    }


    private async getActiveUserRoleName() {
        console.log(this.role);
        this.activeUserRoleNameSubject.next(this.role);
    }


    
    private getActiveUserRoleName$(): Observable<string> {
        return this.activeUserRoleNameSubject.asObservable();
    }

当我像这样传递参数时:

      <button [ticketingPrimeCreateTicketButtonActive]="(this.activeUserRoleName$ | async )"  class="col-1 add"  [ngClass]="{ addInSmall: isSmallOrXSmall() }" (click)="addTicket()">
        <span class="material-icons add-icon"> add_to_photos </span>
      </button>

指令总是接收 null!

我知道如果必须成为 lifecicle 的东西但我已经尝试了所有我认为应该起作用的东西它对我说不不不

编辑:

使用各种 console.logs,我发现问题是它在 ngoninit 从 DDBB 获取值之前抛出指令。

但是我以前不知道怎么做。

编辑 2(已修复):

我终于让它工作了,使 DDBB 在指令内部进行咨询。

但我仍然不知道是否可以在加载模板之前解决组件中的数据库查询,因为在构造函数中我不能使用异步等待。

另一个解决方案是使用解析器来延迟您的组件。 当它命中 ngOnInit 时,该值将已经从数据库中获取。看看 Angular resolvers

据我所知,您的问题显然是组件和指令构建的生命周期。 指令被创建并在那时从它的输入 ticketingPrimeCreateTicketButtonActive 中获取值,因为它是一个数据库获取,很可能是空的。它会继续监听这个值,但不会执行你想要的和在 ngOnInit 中定义的行为,因为这个生命周期事件只发生一次。

我可以看到至少 2 种可能的解决方法。

第一

您可以放弃使用自定义指令并依赖 [hidden]="logicHere"。 通过使用渲染器来操纵 HTML 并不是很常见的做法。 它看起来像这样:

<button [hidden]="!((this.activeUserRoleName$ | async ) === 'Administrator' ||  (this.activeUserRoleName$ | async ) === 'Comercial')"  class="col-1 add"  [ngClass]="{ addInSmall: isSmallOrXSmall() }" (click)="addTicket()">
        <span class="material-icons add-icon"> add_to_photos </span>
      </button>

或者只是用自定义函数替换 hidden 里面的逻辑。

第二

您可以继续您的自定义指令逻辑,但您需要更改 @Input 的管理方式。 Angular 有一个很好的页面解释了这一点:https://angular.io/guide/component-interaction

结果是这样的:

import { Directive, ElementRef, Input, OnInit, Renderer2 } from '@angular/core';

@Directive({
  selector: '[ticketingPrimeCreateTicketButtonActive]'
})
export class CreateTicketButtonActiveDirective implements OnInit {
  @Input() 
  get ticketingPrimeCreateTicketButtonActive() {
     return this._ticketingPrimeCreateTicketButtonActive; 
  };
  set ticketingPrimeCreateTicketButtonActive(ticketingPrimeCreateTicketButtonActive: string){
     this._ticketingPrimeCreateTicketButtonActive = ticketingPrimeCreateTicketButtonActive;
     this.customFunction();
  }
  private _ticketingPrimeCreateTicketButtonActive = '';
  constructor(private elRef: ElementRef, private renderer: Renderer2) {}

  customFunction() {
    if (!(this._ticketingPrimeCreateTicketButtonActive === 'Administrador' || this._ticketingPrimeCreateTicketButtonActive === 'Comercial')) {
      this.renderer.setAttribute(this.elRef.nativeElement, 'hidden', 'true');
    } else {
      this.renderer.setAttribute(this.elRef.nativeElement, 'hidden', 'false');
    }
  }
}

此处,每次 @Input 的值更改时都会调用 customFunction