Недавно мне пришлось реализовать представление popover со многими вариантами, основанными на сложных условиях. Использование ngSwitch в этом случае было невозможно, а использование ngIf нечитабельно и многословно.

Вот как я решил подойти к этой проблеме. Первым шагом было создание директивы с именем TemplateIdDirective:

@Directive({
  selector: 'ng-template[id]',
  standalone: true
})
export class TemplateIdDirective {
  @Input() id: string;
  
  tpl = inject(TemplateRef);
}

Директива нацелена на шаблоны с вводом id. Затем я создал варианты в шаблоне компонента и присвоил каждому id:

<-- trace-information.component.html -->

<div>
  <p>{{ header }}</p>
  <ng-template [ngTemplateOutlet]="body"></ng-template>
</div>

<ng-template id="variation-one">...</ng-template>
<ng-template id="variation-two">...</ng-template>
<ng-template id="variation-three">...</ng-template>
<ng-template id="variation-four">...</ng-template>
<ng-template id="variation-five">...</ng-template>

Наконец, я написал всю логику в компоненте, получил ссылку на шаблоны и отрендерил тот, который совпал:

@Component({
  selector: 'app-trace-information',
  standalone: true,
  imports: [TemplateIdDirective],
  templateUrl: './trace-information.component.html'
})
export class TraceInformationComponent {
  header = '';

  @Input() traceInfo: TraceInfo;
  
  @ViewChildren(TemplateIdDirective) 
  templates: QueryList<TemplateIdDirective>;
  
  private cdr = inject(ChangeDetectorRef);

  ngAfterViewInit() {
    this.resolveView();
  }
 
  private resolveView() {
    // All the complex conditions are defined here.
    // In real life is way more complicated than that.
    // This is only for illustration
    if(...) {
      this.header = '...';
      this.body = this.getTemplate('variation-one');
    } else if(...) {
       if(...) {
         this.header = '...';
         this.body = this.getTemplate('variation-two'); 
       } else {
         this.header = '...';
         this.body = this.getTemplate('variation-three');
       }
    }

    this.cdr.detectChanges();
  }


  private getTemplate(id: string) {
    return this.templates.find((tpl) => tpl.id === id).tpl;
  }
}

Создание компонента для каждого варианта привело бы к тому же результату, но в этом случае представление крошечное, поэтому создание компонента для каждого варианта было бы излишним.

Подпишитесь на меня в Medium или Twitter, чтобы узнать больше об Angular и JS!