在结构指令中声明变量

时间:2019-03-28 09:31:06

标签: angular angular2-directives

我在我的角度应用程序中有一个自定义的结构指令,如下所示:

@Directive({
  selector: '[appIfData]'
})
export class IfDataDirective {

  private hasView = false;

  @Input()
  set appIfData(condition: boolean) {
    if (condition && !this.hasView) {
      this.viewContainerRef.clear();
      this.viewContainerRef.createEmbeddedView(this.templateRef);
      this.hasView = true;
    } else if (!condition) {
      this.viewContainerRef.clear();
      const factory = this.componentFactoryResolver.resolveComponentFactory(ContentMessageComponent);
      const messageComponentRef = this.viewContainerRef.createComponent(factory);
      messageComponentRef.instance.message = 'No data is available yet';
      messageComponentRef.instance.icon = 'fas fa-info';
      this.hasView = false;
    }
  }
}

在html模板中使用它:

<ng-container *appIfData="(referenceService.documentUserTypes$ | async) as userDocTypes">

但是我无法像在使用ngIf时那样在模板的其余部分访问声明的变量'userDocTypes'。

我认为这是正常现象,但我找不到解决此问题的好方法。

任何帮助将不胜感激。

编辑:

这是我使用它的方式,它在子元素中。 如前所述,如果我将其更改为* ngIf:

enter image description here

编辑2:

更新的指令

@Directive({
  selector: '[appIfData]'
})
export class IfDataDirective {

  private hasView = false;

  @Input()
  set appIfData(data: any) {
    if (data && !this.hasView) {
      this.viewContainerRef.clear();
      this.viewContainerRef.createEmbeddedView(this.templateRef, { appIfData: data });
      this.hasView = true;
    } else if (!data) {
      this.viewContainerRef.clear();
      const factory = this.componentFactoryResolver.resolveComponentFactory(ContentMessageComponent);
      const messageComponentRef = this.viewContainerRef.createComponent(factory);
      messageComponentRef.instance.message = 'No data is available yet';
      messageComponentRef.instance.icon = 'fas fa-info';
      this.hasView = false;
    }
  }

3 个答案:

答案 0 :(得分:3)

as中声明的变量只能在其子元素中访问,例如

<ng-container *appIfData="(referenceService.documentUserTypes$ | async) as userDocTypes">
     <div>{{ userDocTypes }}</div>  // you can access here
</ng-container>

<div>{{ userDocTypes }}</div> // you cannot access here

我认为您对template reference感到困惑,可以在其模板中对其进行访问

<div>
    <input type="text" #myInput value="123">
</div>

<div>{{ myInput.value }}</div> // you can access template variable outside of it

答案 1 :(得分:2)

在他的回答中看到t安德烈评论后,我正在使用它:

 /**
     * Cache for document user types
     */
    public documentUserTypesCache$: BehaviorSubject<DocumentUserType[]>;

    /**
     * Get document user types
     */
    public get documentUserTypes$(): BehaviorSubject<DocumentUserType[]> {
        if (!this.documentUserTypesCache$) {
            this.documentUserTypesCache$ = new BehaviorSubject<DocumentUserType[]>([]);
            this.getDocumentUserTypes().pipe(tap(r => this.documentUserTypesCache$.next(r))).subscribe();
        }
        return this.documentUserTypesCache$;
    }

并将其更改为此:

/**
 * Cache for document user types
 */
public documentUserTypesCache$: BehaviorSubject<DocumentUserType[]>;

/**
 * Get document user types
 */
public get documentUserTypes(): DocumentUserType[] {
    if (!this.documentUserTypesCache$) {
        this.documentUserTypesCache$ = new BehaviorSubject<DocumentUserType[]>(null);
        this.getDocumentUserTypes().pipe(
            filter(r => r && r != null),
            tap(r => this.documentUserTypesCache$.next(r))).subscribe();
    }
    return this.documentUserTypesCache$.getValue();
}

不是最好的,但是解决方法有效

答案 2 :(得分:1)

您可以像这样将上下文添加到createEmbeddedView

this.viewContainerRef.createEmbeddedView(this.templateRef, {appIfData: condition});

还请注意,示例中的condition不是布尔值,它可能会在aot编译期间崩溃。将条件类型更改为其他内容