Объявить переменную в структурной директиве - PullRequest
3 голосов
/ 28 марта 2019

У меня есть специальная структурная директива в моем угловом приложении, например:

@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">

Но я не могу получить доступ к объявленной переменной userDocTypes в остальной части шаблона, как я делал, например, при использовании ngIf.

Я думаю, это нормальное поведение, но я не могу найти хороший способ сделать это.

Любая помощь будет принята с благодарностью.

РЕДАКТИРОВАТЬ:

Вот как я это использую, это в дочернем элементе. Как уже было сказано, он работает нормально, если я просто изменил его на * 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 ]

3 голосов
/ 28 марта 2019

переменная, объявленная в 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
2 голосов
/ 28 марта 2019

Посмотрев комментарий Андрея в его ответе, я использовал это:

 /**
     * 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();
}

не самый лучший, но обходной путь работает

1 голос
/ 28 марта 2019

вы можете добавить контекст к createEmbeddedView, как это

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

также обратите внимание, что condition не булево в ваших примерах, оно может привести к сбою во время компиляции. изменить тип условия на другой

...