https://github.com/angular/angular
Raw File
Tip revision: a16e3b8fe1f77b163b0763c263d98f275a6c038c authored by Dylan Hunn on 27 September 2023, 20:21:49 UTC
release: cut the v16.2.7 release
Tip revision: a16e3b8
app.component.html
<!-- #docplaster -->
<!-- #docregion -->
<h1>&lt;ng-container&gt;</h1>

<div *ngIf="hero">{{hero.name}}</div>

<hr>

<h3>&lt;ng-container&gt; and CSS</h3>
<p>Examples demonstrating issues with rigid CSS styles.</p>

<button type="button" (click)="hero = hero ? null : heroes[0]">Toggle hero</button>

<h4>#1 &lt;ng-container&gt; and &lt;p&gt;</h4>
<p>
  I turned the corner
  <ng-container *ngIf="hero">
    and saw {{hero.name}}. I waved
  </ng-container>
  and continued on my way.
</p>
<p>
  I turned the corner
  <span *ngIf="hero">
    and saw {{hero.name}}. I waved
  </span>
  and continued on my way.
</p>

<h4>#2 &lt;ng-container&gt; and &lt;p&gt;</h4>

<div *ngIf="hero">
  <p>
    {{hero.name}} is
    <ng-container *ngFor="let trait of heroTraits; let first=first; let last=last">
      <ng-container *ngIf="!first">,</ng-container>
      <ng-container *ngIf="last">and</ng-container>
      {{trait}}
    </ng-container>.
  </p>

  <p>
    {{hero.name}} is
    <span *ngFor="let trait of heroTraits; let first=first; let last=last">
      <span *ngIf="!first">,</span>
      <span *ngIf="last">and</span>
      {{trait}}
    </span>.
  </p>

<br>

<h4>#3 &lt;ng-container&gt; and &lt;p&gt;</h4>
  <p>
    <label for="showId"><input id="showId" type="checkbox" [checked]="showId" (change)="showId=!showId">Show ID</label>
  </p>

  <div>
    The <code>hero.id</code> in the &lt;span&gt;
    is caught by the <span>p-span</span> CSS:
    <p>
      <span *ngIf="showId">
        Id: ({{hero.id}})
      </span>
      Name: {{hero.name}}
    </p>
  </div>

  <div>
    The <code>hero.id</code> in the &lt;ng-container&gt;
    is unaffected by the <span>p-span</span> CSS:
    <p>
      <ng-container *ngIf="showId">
        Id: ({{hero.id}})
      </ng-container>
      Name: {{hero.name}}
    </p>
  </div>

  <div>
    The <code>hero.id</code> in the &lt;ng-template *ngIf&gt; disappears:
    <p>
      <ng-template *ngIf="showId">
        Id: ({{hero.id}})
      </ng-template>
      Name: {{hero.name}}
    </p>
  </div>

  <div>
    The <code>hero.id</code> in the &lt;ng-template [ngIf]&gt;
    is unaffected by the <span>p-span</span> CSS:
    <p>
      <ng-template [ngIf]="showId">
        Id: ({{hero.id}})
      </ng-template>
      Name: {{hero.name}}
    </p>
  </div>

</div>

<hr>

<h3>&lt;ng-container&gt; and layout-sensitive elements</h3>
<p>
  Examples demonstrating issues with layout-sensitive elements
  such as &lt;select&gt; and &lt;table&gt;.
</p>

<h4>#1 &lt;ng-container&gt; and &lt;options&gt;</h4>

<p><em>&lt;select&gt; with &lt;span&gt;</em></p>
<div>
  Pick your favorite hero
  (<label for="favorite-hero">
    <input id="favorite-hero" type="checkbox" checked (change)="showSad=!showSad">
    show sad
  </label>)
</div>
<select [(ngModel)]="hero">
  <span *ngFor="let h of heroes">
    <span *ngIf="showSad || h?.emotion !== 'sad'">
      <option [ngValue]="h">{{h.name}} ({{h?.emotion}})</option>
    </span>
  </span>
</select>

<p><em>&lt;select&gt; with &lt;ng-container&gt;</em></p>
<div>
  Pick your favorite hero
  (<label for="show-sad"><input id="show-sad" type="checkbox" checked (change)="showSad=!showSad">show sad</label>)
</div>
<select [(ngModel)]="hero">
  <ng-container *ngFor="let h of heroes">
    <ng-container *ngIf="showSad || h?.emotion !== 'sad'">
      <option [ngValue]="h">{{h.name}} ({{h?.emotion}})</option>
    </ng-container>
  </ng-container>
</select>

<br><br><br><br>

<h4>#2 &lt;ng-container&gt; and &lt;options&gt;</h4>
<p>
  <label for="default-traits" (change)="traitPicker.value=showDefaultTraits ? 'loyal' : heroTraits[0]">
    <input id="default-traits" type="checkbox"
          [checked]="showDefaultTraits"
          (change)="showDefaultTraits=!showDefaultTraits">Show default traits
  </label>
</p>

<p>Options with &lt;ng-container&gt;</p>

<select #traitPicker>
  <ng-container *ngIf="showDefaultTraits">
    <!-- Default traits -->
    <option value="loyal">LOYAL</option>
    <option value="clean">CLEAN</option>
    <option value="reverent">REVERENT</option>
  </ng-container>
  <option *ngFor="let trait of heroTraits" [value]="trait">
    {{ trait | uppercase }}
  </option>
</select>


<p>Options with &lt;span&gt;</p>
<select>
  <!-- Default traits are always excluded because intermediate <span> is illegal -->
  <span *ngIf="showDefaultTraits">
    <option value="loyal">LOYAL</option>
    <option value="clean">CLEAN</option>
    <option value="reverent">REVERENT</option>
  </span>
  <option *ngFor="let trait of heroTraits" [value]="trait">
    {{ trait | uppercase }}
  </option>
</select>

<br>

<h4>&lt;ng-container&gt; and &lt;table&gt;</h4>
<p>
  <label for="attrDirs">
    <input id="attrDirs" type="checkbox" checked (change)="attrDirs=!attrDirs">
    Attribute directives
  </label>
  <label for="strucDirs">
    <input id="strucDirs" type="checkbox" checked (change)="strucDirs=!strucDirs">
    Structural directives
  </label>
  <label for="divNgIf">
    <input id="divNgIf" type="checkbox" (change)="divNgIf=!divNgIf">
    div with *ngIf
  </label>
</p>

<table>
  <tr>
    <th style="width:20%">Directive</th>
    <th style="width:10%">Type</th>
    <th>Description</th>
  </tr>

  <tr *ngIf="attrDirs">
    <td>NgClass</td><td>A</td><td>Add or remove multiple CSS classes.</td>
  </tr>

<ng-container *ngIf="divNgIf">
  <div *ngIf="strucDirs">
    <tr>
      <td>xxx</td><td>S</td><td>div with *ngIf formats crazy.</td>
    </tr>
    <tr>
      <td>yyy</td><td>S</td><td>div with *ngIf formats crazy.</td>
    </tr>
  </div>
</ng-container>

  <ng-container *ngIf="strucDirs">
    <tr>
      <td>NgFor</td><td>S</td><td>Repeat the template for each item in a list.</td>
    </tr>
    <tr>
      <td>NgIf</td><td>S</td><td>Add or remove DOM elements.</td>
    </tr>
  </ng-container>

  <ng-container *ngIf="attrDirs">
    <tr>
      <td>NgStyle</td><td>A</td><td>Add or remove multiple style attributes.</td>
    </tr>
  </ng-container>

  <tr *ngIf="strucDirs">
    <td>NgSwitch</td><td>S</td><td>Include in DOM if case matches the switch value.</td>
  </tr>

</table>

<hr>

<h3>Do not confuse &lt;ng-container&gt; with &lt;ng-content&gt;</h3>

<p>&lt;ng-container&gt;Inside ng-container&lt;/ng-container&gt;</p>
<ng-container>Inside ng-container</ng-container>

<p>&lt;ng-content&gt;this is an Angular parse error&lt;/ng-content&gt;</p>
<!--  <ng-content>this is an Angular parse error</ng-content>  -->
<div class="code">Template parse errors:<br>
&lt;ng-content&gt; element cannot have content.</div>

<p>Demo of &lt;/ng-content&gt;</p>
<content-comp>
  Projected content
</content-comp>
back to top