Utilizing lazy loading in conjunction with ngFor to optimize performance

I encountered the error Can't bind to 'ngForOf' since it isn't a known property of 'li'.

Despite trying the suggested solutions, such as importing BrowserModule in the main module (app.module.ts) and importing CommonModule in the child module, I couldn't resolve it.

I'm working on implementing lazy loading and I suspect that the issue might be related to my component structure.

https://i.sstatic.net/jQV2x.png

When using *ngFor in price.component.html, I receive the following error:

<ul>
        <li *ngFor="let book of booksList">{{ book.author }}</li>
    </ul>

    Can't bind to 'ngForOf' since it isn't a known property of 'li'.
    

app.module

import { BrowserModule } from '@angular/platform-browser';
        import { NgModule } from '@angular/core';

        import { AppRoutingModule } from './app-routing.module';
        import { AppComponent } from './app.component';
        import { CoreModule } from './core/core.module';

        import { HttpClientModule } from '@angular/common/http';

        @NgModule({
        declarations: [
            AppComponent
        ],
        imports: [
            BrowserModule,
            AppRoutingModule,
            CoreModule,
            HttpClientModule
        ],
        providers: [],
        bootstrap: [AppComponent]
        })
        export class AppModule { }
    

app-routing.module

import { NgModule } from '@angular/core';
        import { Routes, RouterModule } from '@angular/router';

        const routes: Routes = [
        { path: '', loadChildren: () => import('./landing/landing.module').then(m => m.LandingModule) },
        { path: 'books', loadChildren: () => import('./books/books.module').then(m => m.BooksModule) }
        ];

        @NgModule({
        imports: [RouterModule.forRoot(routes)],
        exports: [RouterModule]
        })
        export class AppRoutingModule { }
    

books.module

import { NgModule } from '@angular/core';
        import { CommonModule } from '@angular/common';

        import { BooksRoutingModule } from './books-routing.module';


        @NgModule({
        declarations: [],
        imports: [
            CommonModule,
            BooksRoutingModule
        ]
        })
        export class BooksModule { }
    

books-routing.module

import { NgModule } from '@angular/core';
        import { Routes, RouterModule } from '@angular/router';
        import { AuthorsComponent } from './authors/authors.component';
        import { PriceComponent } from './price/price.component';
        import { CommonModule } from '@angular/common';

        const routes: Routes = [
        { path: '', component: PriceComponent },
        { path: '/authors', component: AuthorsComponent }
        ];

        @NgModule({
        imports: [RouterModule.forChild(routes), CommonModule],
        exports: [RouterModule],
        declarations: [AuthorsComponent, PriceComponent]
        })
        export class BooksRoutingModule { }
    

EDIT

price.component

import { Component, OnInit } from '@angular/core';
        import { BookInfoService } from '../../book-info.service';

        @Component({
        selector: 'app-price',
        templateUrl: './price.component.html',
        styleUrls: ['./price.component.scss']
        })
        export class PriceComponent implements OnInit {

        booksList={};
        constructor( private httpBooks: BookInfoService ) { }

        ngOnInit(): void {
            this.httpBooks.getBookDetails().subscribe( (result) => {
            this.booksList = result;
            console.log('book list ---> ' + this.booksList);
            })
        }
        }
    

Console output from the price page:

https://i.sstatic.net/A8Zkv.png

Answer №1

@NgModule({
  imports: [RouterModule.forChild(routes), CommonModule],
  exports: [RouterModule],
  declarations: [AuthorsComponent, PriceComponent] // <-- exclude this, it doesn't belong here
})
export class BooksRoutingModule { }
@NgModule({
  declarations: [AuthorsComponent, PriceComponent], // <-- place it here. :)
  imports: [
    CommonModule,
    BooksRoutingModule
  ]
})
export class BooksModule { }

You forgot to share your PriceComponent with us... So..

@Component(...)
export class PriceComponent {
    bookList = [];
}
<ul>
    <li *ngFor="let book of booksList">{{ book.author }}</li>
</ul>

Side note:

const routes: Routes = [
  { path: '', component: PriceComponent },
  { path: '/authors', component: AuthorsComponent }
];

@NgModule({
  declarations: [AuthorsComponent, PriceComponent],
  imports: [
    CommonModule,
    BooksRoutingModule,
    RouterModule.forChild(routes) // <-- functioning
  ]
})
export class BooksModule { }

Update 1:

  • Utilize Resolve and your component will be initialized with valid data. Angular will resolve the data first before loading the component with the resolved data.
// response model. (optional. If not defined, set "Resolve<any>")
interface BookDetailsModel {
  id: number;
  book: string;
  author: string;
}; 

// https://angular.io/api/router/Resolve
@Injectable()
export class BookDetailsResolve implements Resolve<BookDetailsModel> {
  
  constructor(private httpBooks: BookInfoService ) {}

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<BookDetailsModel> | Promise<BookDetailsModel> | BookDetailsModel {
    return this.httpBooks.getBookDetails(); // remember error handling!
  }
}
const routes: Routes = [
  { path: '/authors', component: AuthorsComponent},
  { 
    path: '', 
    component: PriceComponent, 
    resolve: { details: BookDetailsResolve } // <-- include resolver
  }
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule],

  // it works, but it's recommended to add providers to a normal module. I just didn't want to duplicate code. :) 
  providers: [BookDetailsResolve]  // if not a root provider, it needs to be added to a parent or local module.
})
export class BooksRoutingModule { }
@Component({
  selector: 'app-price',
  templateUrl: './price.component.html',
  styleUrls: ['./price.component.scss']
})
export class PriceComponent implements OnInit {

  // typed attribute helps your IDE. :)
  booksList: BookDetailsModel[] = []; // objects cannot be iterated, so I set it to an array.
  constructor(private route: ActivatedRoute) { }

  ngOnInit(): void {
    this.booksList = this.route.snapshot.data.details; // resolve key name will be data.KEY. It will be a normal type, not Observable.
  }
}

Answer №2

Ensure that your component is properly defined within the module file.

@NgModule({
  declarations: [PriceComponent, AuthorsComponent],
  imports: [
    CommonModule,
    BooksRoutingModule
  ]
})
export class BooksModule { }

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

The button event listener in React fails to trigger without a page refresh

Within my index.html file, I have included the following code snippet: <head> ... <script type="text/javascript" src="https://mysrc.com/something.js&collectorId=f8n0soi9" </script> <script ...

What is the best way to vertically align items within a <div> using CSS in a React application?

The layout of the page looks like this: https://i.sstatic.net/NGCNP.png I am trying to center the Redbox (containing '1') within the "PlayerOneDiv". Similarly, I want to center the yellow box within "PlayerTwoDiv". return ( ...

Proper utilization of ngIf in conjunction with mat-cell

I am attempting to show a specific value only if the item possesses a certain property, but I keep seeing [object Object] instead. Here is my current method: <ng-container matColumnDef="name"> <th mat-header-cell *matHeaderCellDe ...

Incorporating Firebase administrator into an Angular 4 project

Currently encountering an issue while trying to integrate firebase-admin into my angular project. Despite my efforts, I am unable to resolve the error that keeps popping up (refer to the screenshot below). https://i.stack.imgur.com/kdCoo.png I attempted ...

The Material UI Datagrid is failing to display any data

I'm currently facing a challenge that has left me scratching my head. I've implemented Material UI Datagrids, but for some reason, I can't get it to populate with data, and the reason eludes me. Even though the Component profiler shows that ...

Angular version 6 and its routing functionality

Hey there, I need some help with setting up routers in my Angular app. Here is the code from my files: import {NgModule} from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; const APP_ROUTES: Routes = [ {pa ...

Customized IntelliSense naming for overloaded parameters with conditional tuple types

In TypeScript 3.1, I have a generic function with arguments of either (TInput, string) or (string), depending on whether the generic's type parameter TInput extends undefined. To achieve this, I'm utilizing the new generic rest parameters feature ...

Importing Json in Angular 8: A detailed guide

I recently came across information that you can now directly import JSON in TypeScript 2.9 and made changes to my tsconfig.json file accordingly: { "compileOnSave": false, "compilerOptions": { "baseUrl": "./", "outDir": "./dist/out-tsc", " ...

Allow Ionic to exclusively work on Android smartphones

When developing an app using Ionic for iOS, you have the option in Xcode to easily specify if the app should be compatible with iPhone, iPad, or both. Is there a similar feature available for Android where I can limit the app's availability based on ...

Navigating the world of TypeScript and SystemJS without the confines of Angular

Lately, I've been delving into TypeScript through research and simple "hello world" projects. However, I've hit a roadblock when it comes to using System.js with TypeScript that I just can't seem to overcome. Most tutorials and demos online ...

Nested ControlGroup in Angular2's ControlArray

I've hit a roadblock trying to iterate through a ControlArray that has Controlgroups in a template. In TypeScript, I successfully created the ControlArray and added some ControlGroups by looping over data fetched from an API. The console displays the ...

Issue: "The argument provided must be a specific string, not a string or an array of strings."

Currently, I am tackling a Vue project that incorporates TypeScript and axios for handling API requests. While working on the Reset Password component, the resetPassword function within the auth.ts file appears as follows: resetPassword(password1: string, ...

Is there a way to seamlessly transition between different Angular components without having to refresh the entire webpage?

I'm currently working on implementing a navigation bar that allows users to switch between three components without having the navbar reload. The goal is for only the new component to load when the user clicks on a different section of the navbar, kee ...

The compiler is showing an error with code TS5023, indicating that the option 'strictTemplates' is not recognized

When trying to compile my Angular application (v10), I encountered the following error message. An unexpected issue has occurred: tsconfig.json:14:5 - error TS5023: Unknown compiler option 'strictTemplates'. 14 "strictTemplates": t ...

Share your Angular Elements web component as an npm module

Is there a way to package an Angular app as an npm module, especially when it is wrapped as a web component using Angular Elements? I'm interested in seamlessly importing the web component into another application through npm, rather than manually inc ...

Guide to incorporating ThreeJS Collada loader with TypeScript / Angular CLI

I currently have three plugins installed: node_modules/three My Collada loader was also successfully installed in: node_modules/three-collada-loader It seems that the typings already include definitions for the Collada loader as well: node_modules/@ty ...

I encountered difficulties connecting mongoose to my local MongoDB server

Hello Everyone! Currently, I am in the process of linking my node.js project to mongodb. Initially, everything worked smoothly when I used mongodb atlas. However, when I attempted to connect it using mongodb compass, I faced some issues and nothing seemed ...

Struggling to import a React component for sharing purposes

I've developed a React component that I want to share through a locally hosted npm repository. To achieve this, I created the React component using typescript, transpiled it to JavaScript, and then published the resulting code to the repository. Howe ...

Access the value of a BehaviorSubject within an Angular component

Seeking assistance with creating a comparison in my component where I want to display a message if successful, or redirect to another page after 3 seconds if not. However, I am unsure how to check for NULL with this *(this.link$.source.value.success) or (t ...

Break free/Reenter a function within another function

Is there a way to handle validation errors in multiple task functions using TypeScript or JavaScript, and escape the main function if an error occurs? I am working in a node environment. const validate = () => { // Perform validation checks... // ...