skip to Main Content

I am trying to conditionally display <ng-content> within a <div> based on a condition. However, for some reason, the <ng-content> inside the <div> never gets shown, even when the condition is true. The content renders correctly under the @else block, but when the @if condition is met, the content in the <div> is not visible.

Here is a simplified version of the code:

<app-header />
<div class="container">
  @if (innerWidth <= 768) {
    @if (open()) {
      <div class="container2" style="width: 450px; z-index: 15;">
        <ng-content />
      </div>
    }
  } @else {
    <ng-content />
  }
  <!-- <app-vehicles /> -->
  <!-- <app-tracking-data /> -->
  <app-map />
</div>

Expected Behavior:
The <ng-content> inside the @if block should be shown when innerWidth <= 768 and open() returns true.

Actual Behavior:
The <ng-content> within the conditional <div> never gets displayed, while the content in the @else block works as expected.

2

Answers


  1. You facing an XY issue. You’re trying to apply a solution for a media query not to the document but to a container. As media query does not work that way, you trying to dynamically manipulate the DOM as a solution.

    Instead of fixing your question at hand I going to fix your actual problem that does not even require your attempt.

    As said above, media queries only work on the entire document or screen. If you want a CSS query specifically for a block-level element you have to use container query:

    @container (max-width: 768px) {
      .container {
        width: 450px;
        z-index: 15;
      }
    }
    
    Login or Signup to reply.
  2. What you are trying to achieve should be simply done using pure CSS. But I want to make it clear, that rendering ng-content inside conditionals is bad (point of my answer).


    It is discouraged to show ng-content inside conditionals as per documentation Content projection with ng-content.

    You should not conditionally include with @if, @for, or @switch. Angular always instantiates and creates DOM nodes for content rendered to a placeholder, even if that placeholder is hidden. For conditional rendering of component content, see Template fragments.

    Instead use ContentChild to get the data and show it.

    import {
      Component,
      contentChild,
      ContentChild,
      signal,
      TemplateRef,
      Signal,
    } from '@angular/core';
    import { CommonModule } from '@angular/common';
    import { bootstrapApplication } from '@angular/platform-browser';
    
    @Component({
      selector: 'app-child',
      standalone: true,
      imports: [CommonModule],
      template: `
        <div class="container">
            @if (open()) {
              <div class="container2" style="background-color: red;width: 450px; z-index: 15;">
                <ng-container *ngTemplateOutlet="content()"></ng-container >
              </div>
            } @else {
                <ng-container *ngTemplateOutlet="content()"></ng-container >
            }
        </div>
      `,
    })
    export class Child {
      content: Signal<any> = contentChild('content');
      name = 'Angular';
      open = signal(true);
    
      ngAfterContentInit() {
        setInterval(() => {
          this.open.set(!this.open());
        }, 1000);
        console.log(this.content);
      }
    }
    
    @Component({
      selector: 'app-root',
      standalone: true,
      imports: [Child],
      template: `
      <app-child>
        <ng-template #content>
        <h1>Hello from {{ name }}!</h1>
        <a target="_blank" href="https://angular.dev/overview">
          Learn more about Angular
        </a>
      </ng-template>
    </app-child>
      `,
    })
    export class App {
      name = 'Angular';
    }
    
    bootstrapApplication(App);
    

    Stackblitz Demo

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search