Is it Possible for Angular Layout Components to Render Content Correctly even with Deeply Nested ng-container Elements?

Within my Angular application, I have designed a layout component featuring two columns using CSS. Within this setup, placeholders for the aside and main content are defined utilizing ng-content.

The data for both the aside and main sections is fetched from the server. A loading flag is set during the loading phase to signify that data retrieval is in progress. Once successful data retrieval occurs, an isSuccess flag is returned alongside the response from the observable.

To replicate this process, I've crafted a mock data$ observable with the help of the RxJS of operator. This observable includes a delay to mirror the asynchronous nature of data retrieval.

An issue has surfaced where the layout fails to properly render the aside and main content. This problem arises due to the fact that the ng-content directive anticipates the attributes aside and main directly, but they exist deeply nested inside ng-container.

The question at hand is whether it's feasible to modify this setup to correctly showcase the content?

Below is the revised code snippet:

import { CommonModule } from '@angular/common';
import { Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { delay, of, startWith } from 'rxjs';
import 'zone.js';

@Component({
  selector: 'layout',
  standalone: true,
  template: `
    <div class="container">
      <aside>
        <ng-content select="[aside]"></ng-content>
      </aside>
      <main>
        <ng-content select="[main]"></ng-content>
      </main>
    </div>
  `,
  styles: [`.container {display:grid; grid-template-columns: 1fr 2fr} `],
})
export class LayoutComponent {}

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [LayoutComponent, CommonModule],
  template: `
    <layout>
      <ng-container *ngIf="data$ | async as result">
        <div *ngIf="result.loading">loading...</div>
        <ng-container *ngIf="result.isSuccess">
          <div aside>aside content: {{ result.response.aside | json }}</div>
          <div main>main content: {{ result.response.main | json }}</div>
        </ng-container>
      </ng-container>
    </layout>
  `,
})
export class App {
  data$ = of<any>({ 
    response: { aside: [1, 2, 3, 4], main: [10, 12, 13, 14] },
    isSuccess: true,
  }).pipe(delay(1 * 1000), startWith({ loading: true }));
}

bootstrapApplication(App);

Access the code at this link: StackBlitz

Answer №1

When using ng-content tags, it's important for them to be at the top level in order to be visible for content projection.

I've made changes to the HTML structure so that we can retrieve data and display content conditionally based on specific conditions. By leveraging if else (ng-template), we can incorporate a loading section as needed!

Feel free to adjust the code according to your preferences and requirements!

Here is the full revised code:

import { CommonModule } from '@angular/common';
import { Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { delay, of, startWith } from 'rxjs';
import { endWith } from 'rxjs/operators';
import 'zone.js';
console.clear();

@Component({
  selector: 'layout',
  standalone: true,
  template: `
    <div class="container">
      <aside>
        <ng-content select="[aside]"></ng-content>
      </aside>
      <main>
        <ng-content select="[main]"></ng-content>
      </main>
    </div>
  `,
  styles: [`.container {display:grid; grid-template-columns: 1fr 2fr} `],
})
export class LayoutComponent {}

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [LayoutComponent, CommonModule],
  template: `
    <ng-container *ngIf="data$ | async as result">
      <layout *ngIf="result.isSuccess;else loading">
        <div aside>aside content: {{ result.response.aside | json }}</div>
        <div main>main content: {{ result.response.main | json }}</div>
      </layout>
    </ng-container>
    <ng-template #loading>
      <div>loading...</div>
    </ng-template>
  `,
})
export class App {
  name = 'Angular';

  data$ = of<any>({
    response: { aside: [1, 2, 3, 4], main: [10, 12, 13, 14] },
    isSuccess: true,
  }).pipe(delay(1 * 1000), startWith({ loading: true }));
}

bootstrapApplication(App);

Check out the Stackblitz Demo

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Troubleshooting the Gutter Problem in jQuery Isotope and Masonry

Currently, I am utilizing the Isotope jQuery plugin. While it is a fantastic tool, I am encountering a minor issue with aligning items in masonry mode. The width of my container is 960px, and I aim to have 4 items perfectly aligned as if they were adhering ...

How can I test Angular Router using Jest?

I'm currently experimenting with testing the functionality of a collapsed element in a sidebar when a user navigates to a specific page. I'm encountering some challenges in trying to simulate the behavior of the Angular Router in my Jest tests. ...

What is the best way to minimize the number of requests sent in AngularJS?

Currently in my demo, each time a user types something into an input field, a request is sent to the server. However, I would like only one request to be fired. For example, if the user types "abc," it currently fires three requests. Is there a way for the ...

Troubleshooting GLSL scripts within a web-based WebGL environment

Are there ways to debug GLSL code or display variable values directly from within the GLSL code when using it with WebGL? Does three.js or scene.js offer any features for this purpose? ...

Is it necessary to retrieve the data that was posted from the back-end? Implementation using Angular and Node.js

I need some advice on how to handle worker data in my Angular, NodeJS, and MySQL app. In the FORM, users can add workers whose information is then sent to the backend for processing. The user can preview the posted information and delete workers if needed. ...

Having trouble getting a form to submit to a Rails server using AJAX in IE11 with jQuery

Currently, I'm attempting to transfer data from a form to a Rails server using AJAX. The form consists of two text inputs and one file input. Below is the code for my submit event handler: $("form").on("submit", function(event) { event.preventDefa ...

Troubleshooting jQuery masonry problem related to initial display and height settings

Within a div, there is a masonry container with the inline style property display:none. With several divs on the page, clicking their respective buttons during load causes them to switch like a slideshow. This disrupts masonry's ability to calculate t ...

Troubleshooting image loading issues when updating the base URL in an Angular JS project

I am trying to update the base URL for my application. Currently, when I load the application, the URL shows up as http://localhost:4200/#/, but I want it to be http://localhost:4200/carrom/ instead. To accomplish this, I modified the base URL and now th ...

Looking to add a dropdown feature to my current main navigation bar

I've been struggling to add a drop-down menu to my website's main menu. Every time I try, something goes wrong - sometimes the menu appears inline, other times it completely messes up the layout. Here is the HTML code snippet: <ul class="m ...

Implementing the requiredUnless validator of vuelidate for checkboxes: A step-by-step guide

When utilizing Vuelidate, the 'required' validator now accepts boolean 'false' as a valid value. To enforce required validation for checkboxes, you must use 'sameAs' such as sameAs: sameAs( () => true ). How can 'requi ...

Guide on setting a wait while downloading a PDF file with protractor

As I begin the download of a pdf file, I realize that it will take more than 2 minutes to complete. In order to verify if the file has successfully downloaded or not, I will need to wait for the full 2 minutes before performing any verification checks. C ...

Test your knowledge of Javascript with this innerHtml quiz and see

How can I display the output of a score from a three button radio button quiz without using an alert popup? I want the output to be displayed within a modal for a cleaner look. I tried using InnerHTML but now there is no output when the button is clicked. ...

What are the steps to correctly implement async await in a standard sequence?

When I press the button onPress={() => Login()} First, I need to obtain a token by using the signInWithKakao function. Secondly, right after acquiring the token, if it is available, I want to dispatch the profile using the kakaoprofile function. Howev ...

Unordered list in Bootstrap Collapse not responding after initial click

I recently created a filetree page on my website and incorporated some bootstrap collapse elements that seem to function as intended. However, I am encountering an issue where the folder content does not collapse upon clicking the folder symbol (button) fo ...

Discovering the names of files in a directory with Angular

Looking for a solution in Angular JS within a ModX app to retrieve file names from the gallery package every time it is updated. Is there a way to achieve this using Angular? I've been searching for Javascript solutions to this issue, but most of the ...

The Nuxt content Type 'ParsedContent | null' cannot be assigned to type 'Record<string, any> | undefined'

I've been experimenting with @nuxt/content but I'm struggling to create a functional demo using a basic example. ERROR(vue-tsc) Type 'ParsedContent | null' is not assignable to type 'Record<string, any> | undefined'. ...

Express.js encounters a 404 error when router is used

I am currently in the process of learning and consider myself a beginner at Node.js. My goal is to create a basic REST API, but I keep encountering an error 404 when attempting to post data to a specific route using Postman to test if the information has b ...

Unable to access a hyperlink, the URL simply disregards any parameters

When I click an a tag in React, it doesn't take me to the specified href. Instead, it removes all parameters in the URL after the "?". For example, if I'm on http://localhost:6006/iframe.html?selectedKind=Survey&selectedStory=...etc, clicking ...

Accept only numerical values, addition and subtraction symbols, commas, the F5 key, and various other characters

I want to restrict key strokes to only numbers (including those on the numpad), minus (-) and plus (+) signs, and commas (,). Currently, it types twice when I input a number (e.g. 2 is displayed as 22) and replaces the current value with the new number. F ...

What could be the reason for v-model not functioning properly?

Embarking on my Vue.js coding journey, I am currently following a straightforward online tutorial. Utilizing the vue-cli, I kickstarted my application and crafted a basic component named Test.vue. Within this component lies a simplistic input control conne ...