Рендеринг динамического шаблона на основе типа - PullRequest
1 голос
/ 28 октября 2019

Мне очень нравится ответ, предоставленный для Динамический шаблон, основанный на значении, а не на переменной с ngTemplateOutlet . Однако я не могу заставить его работать. Упрощенный пример:

export class A {
}

export class MyComponent 
  implements OnInit {

  public controls$ = Observable<any[]>([]);

  ngOnInit() {
    this.controls$.next([new A()]);
  }

  public getTypeName(control: any) {
    if (control instanceof A) {
      return "AControl";
    }
    return "";
  }
}

Шаблон:

<div *ngFor="let control of control$ | async">
  {{ getControlType(control) }}
</div>

Выход:

AControl

Пока все хорошо. Когда я добавляю шаблон, я получаю исключение:

<div *ngFor="let control of control$ | async">
  {{ getControlType(control) }}
  <ng-container 
    [ngTemplateOutlet]="getControlType(control)"
    [ngTemplateOutletContext]="{ control: control }">
  </ng-container>
</div>

<ng-template 
  #AControl 
  let-item="control">A Control</ng-template>

throws:

templateRef.createEmbeddedView не является функцией

I'mне уверен, что мне нужно изменить, чтобы шаблон #AControl отображался в контейнере.

Ответы [ 2 ]

1 голос
/ 28 октября 2019

похоже, что [ngTemplateOutlet]="getControlType(control)" является виновником. Я не вижу код для getControlType(), но я предполагаю, что он возвращается в виде строки, в то время как это должен быть TemplateRef объект. Вызов функций в шаблоне не является хорошей идеей, если вы не используете ChangeDetectionStrategy.OnPush, поэтому я предлагаю вместо этого использовать оператор switch в вашем шаблоне. Тем не менее, с помощью

@ViewChild("AControl", {static: true})
AControl: TemplateRef<any>;

вы можете получить доступ к шаблону в вашем файле .ts и вернуться из функции getControlType

0 голосов
/ 28 октября 2019

С помощью ответа D Pro я обнаружил, что мне действительно не нужно использовать ngTemplateOutlet в моем случае (они кажутся действительно сложными для чего-то столь же простого, как я использовал).

Мое окончательное решение:

машинопись

export class A {
}

export class B {
}


export class MyComponent 
  implements OnInit {

  public controlsTypes$ = Observable<any[]>([]);

  ngOnInit() {
    var value1 = new A();
    var value2 = new B();
    this.controls$.next([
      { control: value1, type: getTypeName(value1)},
      { control: value2, type: getTypeName(value2)},
    ]);
  }

  public getTypeName(control: any) {
    if (control instanceof A) {
      return "AControl";
    } else if (control instanceof B) {
      return "BControl";
    }
    return "";
  }

  public onClick(control: any) {
  }
}

html:

<div *ngFor="let controlType of controlType$ | async"
     [ngSwitch]="controlType.type">
  <ng-template ngSwitchCase="AControl">
    <div (click)="onClick(controlType.control)">{{ controlType.type }}</div>
  </ng-template>
  <ng-template ngSwitchCase="BControl">
    <div (click)="onClick(controlType.control)">{{ controlType.type }}</div>
  </ng-template>
</div>

Показывает AControl и BControl ипри нажатии каждого из них экземпляр класса передается в onClick().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...