How to make a if-else Angular template with only ng-container?
Asked Answered
S

5

54

I would like to make an if-else statement in my angular template. I started with that :

<ng-container *ngIf="contributeur.deb; else newDeb" >
    [... HERE IS A RESULT 1]
</ng-container>
<ng-template #newDeb>
    [... HERE IS A RESULT 2]
</ng-template>

And I tried to only use ng-container :

<ng-container *ngIf="contributeur.deb; else newDeb" >
    [... HERE IS A RESULT 1]
</ng-container>
<ng-container #newDeb>
    [... HERE IS A RESULT 2]
</ng-container >

Unfortunately, this does not work. I have this error :

ERROR TypeError: templateRef.createEmbeddedView is not a function
    at ViewContainerRef_.createEmbeddedView (eval at <anonymous> (vendor.bundle.js:11), <anonymous>:10200:52)
    at NgIf._updateView (eval at <anonymous> (vendor.bundle.js:96), <anonymous>:2013:45)
    at NgIf.set [as ngIfElse] (eval at <anonymous> (vendor.bundle.js:96), <anonymous>:1988:18)
    at updateProp (eval at <anonymous> (vendor.bundle.js:11), <anonymous>:11172:37)
    at checkAndUpdateDirectiveInline (eval at <anonymous> (vendor.bundle.js:11), <anonymous>:10873:19)
    at checkAndUpdateNodeInline (eval at <anonymous> (vendor.bundle.js:11), <anonymous>:12290:17)
    at checkAndUpdateNode (eval at <anonymous> (vendor.bundle.js:11), <anonymous>:12258:16)
    at debugCheckAndUpdateNode (eval at <anonymous> (vendor.bundle.js:11), <anonymous>:12887:59)
    at debugCheckDirectivesFn (eval at <anonymous> (vendor.bundle.js:11), <anonymous>:12828:13)
    at Object.eval [as updateDirectives] (ActionsButtons.html:5)

Can anyone explain me what is going wrong in this code ?

Skiplane answered 31/5, 2017 at 14:44 Comment(0)
C
110

The code for the ngIf directive expects to be passed a reference to a template (TemplateRef) for the else branch, which it will call createEmbeddedView on to display the nested content. Therefore, it makes no sense to try to use any other kind of element for the else content - it just won't work. You're able to nest an ng-container inside the ng-template if needs be, though.

This might seem unintuitive, but bear in mind that structural directives (i.e. ones that you call with a *) are always represented as ng-template under the hood, no matter what kind of element they're attached to - these two pieces of code are the same:

<ng-container *ngIf="contributeur.deb; else newDeb" >
    ...
</ng-container>
<ng-template #newDeb>
    ...
</ng-template>

<ng-template [ngIf]="contributeur.deb; else newDeb">
    <ng-container>
        ...
    </ng-container>
</ng-template>
<ng-template #newDeb>
    ...
</ng-template>
Counterpart answered 31/5, 2017 at 15:2 Comment(3)
I'd recommend reading the Angular docs page on Structural Directives - it's long, but really informative.Counterpart
I cannot thank you enough for this answer. I spent hours scratching my head trying to solve a null component in a canDeactivate guard.Undoing
@JoeClay Error: src/app/leads/leads-list.component.ts:99:34 - error NG5002: Parser Error: Binding expression cannot contain chained expression at column 7 in [lead; else newDeb] in C:/Users/iii/Desktop/ui-code-challenge-1-master/src/app/leads/leads-list.component.ts@98:33 99 <ng-template [ngIf]="lead; else newDeb">Androus
H
18

I do not love the standard Angular structure for if then else. Then I found an alternative solution with ngSwitch:

<ng-container [ngSwitch]="isFirstChoice(foo) ? 1 : (isSecondChoice(foo) ? 2 : -1)">
  <ng-container *ngSwitchCase="1">
    ...first choice...
  </ng-container>
  <ng-container *ngSwitchCase="2">
    ...second choice...
  </ng-container>
  <ng-container *ngSwitchDefault>
    ...another choice...
  </ng-container>
</ng-container>

To answer to your request I'd use this:

<ng-container [ngSwitch]="contributeur.deb && 'isDeb'">
  <ng-container *ngSwitchCase="'isDeb'">
    ......
  </ng-container>
  <ng-container *ngSwitchDefault>
    ......
  </ng-container>
</ng-container>
Heroism answered 29/11, 2019 at 14:55 Comment(0)
C
6

It bears mentioning that this simple alternative is perhaps more readable than many of the other options. Just using a second ng-container, and just 'not'-ing the condition with an exclamation mark to make the else section.

<ng-container *ngIf="contributeur.deb" >
    [... HERE IS A RESULT 1]
</ng-container>
<ng-container *ngIf="!contributeur.deb">
    [... HERE IS A RESULT 2]
</ng-container >
Commissionaire answered 22/10, 2021 at 23:44 Comment(0)
F
1

As per Angular 17, we can use @if(){} OR @if(){} @else if(){}. after using this , code looks clear and more readable.

@if(contributeur.deb){
   [.....any code]
}
@else {
   [.....any code]
}

like that.

Please go through these reference links.

angular-17-new-control-flow-with-signals

new-control-flow-in-angular-17

Thanks

Fare answered 5/12, 2023 at 7:5 Comment(1)
Control flow indeed solves this issue. For people who are not familiar with it yet, it would be good to add a link to the documentation for further reading. Also the author of the question is looking for an if else, not an if else-if. Maybe you can edit your answer to improve it.Xavier
T
0
@if(condition) {
    ...code
} @else {
    <ng-container *ngTemplateOutlet="someTemplate"></ng-container>
}

<ng-template #someTemplate></ng-template>

Please use ngTemplateOutlet official documentation to discover more!

Thanks!

Theaterintheround answered 3/6, 2024 at 22:3 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Elective

© 2022 - 2025 — McMap. All rights reserved.