0

I have a class section on a DIV to be rendered. It works as expected.

<div *ngIf="decoded; then coordinates"></div>
<ng-template #coordinates>
  <div class="section">...</div>
</ng-template>

I tried moving the class assignment to the DIV containing the directive. The rendition did not work, though.

<div *ngIf="decoded; then coordinates" class="section"></div>
<ng-template #coordinates>
  <div>...</div>
</ng-template>

The outer DIV vanishes as a whole, being replaced by the contents of the template. It bugs me because I'm forced to add an extra DIV around everything in my template if I have several components in it. (Also, it seems kind of weird to me that we don't retain any properties of the tag used with *ngIf and can use any arbitrary one, while it seems to work for *ngFor.)

<div *ngIf="decoded; then coordinates"></div>
<ng-template #coordinates>
  <div class="section">
    <div>...</div>
    <span>...</span>
    <bzz>...</bzz>
  </div>
</ng-template>

I tried cheating the browser by setting the class on template but since it's not actually rendered in the DOM as such, it failed, of course.

<div *ngIf="decoded; then coordinates"></div>
<ng-template #coordinates class="section">
  <div...</div>
</ng-template>

is there a way to force the DIV with the conditional directive to retain its class when being rendered according to the template's contents?

Konrad Viltersten
  • 36,151
  • 76
  • 250
  • 438
  • That happens because you explicitly used `then` to render something _other than_ the element `*ngIf` was on; if you'd just written `
    ...
    ` it would have worked as you expected. Look at the examples of how structural directives are expanded in e.g. https://angular.io/api/common/NgIf#description.
    – jonrsharpe Mar 15 '22 at 09:28

3 Answers3

1

You can try to use ng-container and apply *ngIf to it, in this case it should work as you expected

<div class="section">
  <ng-container *ngIf="decoded; then coordinates"></ng-container>
</div>

<ng-template #coordinates>
  <div>...</div>
</ng-template>
Slawa Eremin
  • 5,264
  • 18
  • 28
  • it still bugs me a bit that in case with `ngFor`, the element with the directive is being rendered (repeatedly) including the its class, while `ngIf` "kills" it. That said, great answer. Quick too! – Konrad Viltersten Mar 15 '22 at 08:02
-1

TL;DR: Angular is doing what you asked it to; you used then to tell it to render something other than the element the directive was on in the truth-y case. If that's not the behaviour you want, don't do that.


Structural directives like *ngIf and *ngFor are really a shorthand that gets expanded (this used to be referred to as "desugaring"), look at the examples in https://angular.io/guide/structural-directives or more specifically https://angular.io/api/common/NgIf#description:

Simple form with shorthand syntax:

<div *ngIf="condition">Content to render when condition is true.</div>

Simple form with expanded syntax:

<ng-template [ngIf]="condition">
    <div>Content to render when condition is true.</div>
</ng-template>

Note that everything gets wrapped up in ng-templates for conditional rendering.


If you had written your template like this:

<div *ngIf="decoded" class="section">...</div>

it would get expanded to:

<ng-template [ngIf]="decoded">
  <div class="section">...</div>
</ng-template>

and what would actually be rendered is:

<div class="section">...</div>

Note that the class is still included, consistent with what you've experienced in other structural directives.


However, when you use then, the shorthand:

<div *ngIf="decoded; then coordinates" class="section"></div>
<ng-template #coordinates>
  <div>...</div>
</ng-template>

is expanded to:

<ng-template [ngIf]="decoded" [ngIfThen]="coordinates">
  <div class="section"></div>
</ng-template>
<ng-template #coordinates>
  <div>...</div>
</ng-template>

The content of the first ng-template is now irrelevant, because that's not what's rendered in either case. It's either going to render the #coordinates template content or nothing, so you get:

<div>...</div>

and your class seems to have disappeared. But that's what you asked for; the point of then is to not render the element the *ngIf was on, in the truth-y case, but to render something else instead.


For more on these underlying ng- elements, I wrote Angular's "ng-" elements on my blog.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
-1

I suggest to take a look on this great article Everything you need to know about ng-template, ng-content, ng-container, and *ngTemplateOutlet in Angula

It contains all you need to know about Angular's structural directives with a good explanation and examples.