Importing BrowserAnimationsModule in the core module may lead to dysfunctional behavior

When restructuring a larger app, I divided it into modules such as feature modules, core module, and shared module. Utilizing Angular Material required me to import BrowserAnimationsModule, which I initially placed in the Shared Module. Everything functioned correctly until I attempted to lazy load certain feature modules - this triggered an error regarding double importing of BrowserModules. It became apparent that BrowserAnimationsModule should be imported by the Core Module, but when I made this adjustment, a new error emerged:

Uncaught Error: Template parse errors:
Can't bind to 'ngForOf' since it isn't a known property of 'mat-option'.
1. If 'mat-option' is an Angular component and it has 'ngForOf' input, then verify that it is part of this module.
2. If 'mat-option' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.
3. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component. ("' | translate}}" (change)="change()" [(ngModel)]="actualFilter" name="food">
          <mat-option [ERROR ->]*ngFor="let filterColumn of displayedColumns" [value]="filterColumn">
            {{filterColumn | t"): ng:///ChargesModule/ChargesComponent.html@9:22
Property binding ngForOf not used by any directive on an embedded template. Make sure that the property name is spelled correctly and all directives are listed in the "@NgModule.declarations". ("COLUMNFILTER' | translate}}" (change)="change()" [(ngModel)]="actualFilter" name="food">
          [ERROR ->]<mat-option *ngFor="let filterColumn of displayedColumns" [value]="filterColumn">
            {{filt"): ng:///ChargesModule/ChargesComponent.html@9:10

The module setup is as follows: app.module.ts:

    @NgModule({
      declarations: [
        AppComponent
      ],
      imports: [
        BrowserModule,
        HomeModule,
        ChargesModule,
        ModeratorPanelModule,
        CoreModule
      ],
      providers: [],
      bootstrap: [AppComponent]
    })

    export class AppModule { }

core.module.ts:

 @NgModule({
      imports: [
        HttpModule,
        HttpClientModule,
        AppRoutingModule,
        SharedModule,
        BrowserAnimationsModule
      ],
      declarations: [
        SidenavComponent,
        HeaderComponent,
        ErrorPageComponent,
        PageNotFoundComponent,
        LoginComponent,
        UpdatePanelComponent,
        DialogConfirmCancelComponent,
        ConfirmMessageComponent,
      ],
      exports: [
        HttpModule,
        HttpClientModule,
        SharedModule,
        HeaderComponent,
        SidenavComponent,
        AppRoutingModule,
        BrowserAnimationsModule
      ],
      providers: [
        AuthService, AuthGuard, HttpAuthService, DictionariesService,
        DictionaryItemFactory, CanDeactivateGuard, { provide: MatPaginatorIntl, useClass: CustomPaginator }
      ],
      entryComponents: [DialogConfirmCancelComponent, ConfirmMessageComponent]
    })
    export class CoreModule { }

shared.module.ts:

export function HttpLoaderFactory(http: HttpClient) {
  return new TranslateHttpLoader(http);
}
@NgModule({
  imports: [
    CommonModule,
    MaterialModule,
    FlexLayoutModule,
    CdkTableModule,
    FormsModule,
    NgbModule.forRoot(),
    TimepickerModule.forRoot(),
    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: HttpLoaderFactory,
        deps: [HttpClient]
      }
    })
  ],
  exports: [
    NgbModule,
    TimepickerModule,
    TranslateModule,
    CurrenciesComponent,
    MaterialModule,
    FlexLayoutModule,
    CdkTableModule,
    FormsModule,
    DropDownListComponent,
    DictionariesComponent
  ],
  declarations: [
    DictionariesComponent,
    DropDownListComponent
  ],
  providers: []
})
export class SharedModule { }

Within the MaterialModule, I included all material modules along with CommonModule.

Answer №1

If you encountered an issue similar to

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

then it may be due to:

  • an undeclared @Input;

  • a configuration problem with @NgModule

Given that ngForOf is a predefined directive, let's delve into the issue related to your @NgModule setup.

Firstly, we must identify the source of this error. The error message provides a clue:

{{filterColumn | t"): ng:///ChargesModule/ChargesComponent.html@9:22

From this, it's evident that the error stems from the ChargesComponent within the ChargesModule. It is likely that the declaration in the ChargesModule resembles:

charges.module.ts

@NgModule({
  imports: [
    SharedModule,
    ...
  ],
  declarations: [
    ChargesComponent,
    ...
  ]
})
export class ChargesModule {}

If you haven't already, I recommend reading my previous answer on Angular 2 Use component from another module for further clarity on utilizing components across modules. Ensure you grasp how components/directives/pipes can be employed in other modules. If unsure, read on...

The key guideline here is

Since we need to utilize the ngForOf directive within the template of the ChargesComponent, which belongs to ChargesModule, the directive should be included in the transitive directives of ChargesModule.

How are these directives gathered?

               ChargesModule.directives 
                         + 
      exported directives from imported @NgModules
                        ||
         ChargesModule.transitiveModule.directives

Initially, one might consider declaring the ngForOf directive in the declarations array of ChargesModule, but as ngForOf is already declared in CommonModule and a directive can only belong to one module, this approach won't suffice.

Hence, continue searching for ngForOf directives among the imported @NgModules. As we imported SharedModule, let's explore the directives it exports:

shared.module.ts

@NgModule({
  ...,
  exports: [
    NgbModule,
    TimepickerModule,
    TranslateModule,
    CurrenciesComponent,
    MaterialModule,
    FlexLayoutModule,
    CdkTableModule,
    FormsModule,
    DropDownListComponent,
    DictionariesComponent
  ]
})
export class SharedModule { }

SharedModule exports all directives that are either

exported from @NgModules

 NgbModule,
 TimepickerModule,
 TranslateModule,
 MaterialModule,
 FlexLayoutModule,
 CdkTableModule,
 FormsModule

This implies that if NgbModule has exported directives, they will be included in the exported directives of SharedModule.

or simply directives listed in the exports array

 CurrenciesComponent,
 DropDownListComponent,
 DictionariesComponent

As CommonModule is not listed here, it indicates that we may encounter the error 'Can't bind to 'ngForOf''

To resolve this, we must add CommonModule to the exports array, after which everything should function properly.

An intriguing question arises

However, I do not understand why this problem occurred only after moving BrowserAnimationsModule from Shared to Core module. Can you explain that?

Understanding this requires insight into the composition of BrowserAnimationsModule. Let's shed light on this by examining the source code:

@NgModule({
  exports: [BrowserModule],
  providers: BROWSER_ANIMATIONS_PROVIDERS,
})
export class BrowserAnimationsModule {
}

and inspecting BrowserModule:

@NgModule({
  ...
  exports: [CommonModule, ApplicationModule]
})
export class BrowserModule {

It becomes apparent that exporting BrowserAnimationsModule module from SharedModule also exports directives from CommonModule because:

SharedModule.transitiveModule.directives
               /\
               ||
   BrowserAnimationsModule exports 
               /\
               ||
     BrowserModule that exports
               /\
               ||   
          CommonModule

Thus, upon relocating BrowserAnimationsModule to CoreModule, SharedModule no longer exports the ngForOf directive, resulting in the error you observed.

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

Encountered a module build error while upgrading Angular Project from version 14 to 15

When attempting to run my project, an error is displayed. ./src/styles.scss?ngGlobalStyle - Error: Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js): HookWebpackError: Module build failed (from ./node_modules/sass-loader/dist ...

Implementing asynchronous validation in Angular 2

Recently started working with Angular 2 and encountered an issue while trying to validate an email address from the server This is the form structure I have implemented: this.userform = this._formbuilder.group({ email: ['', [Validators.requir ...

What is the best way to integrate environment-specific configuration options into an AngularJS and Typescript project?

Currently, I am working on a project using AngularJS, Typescript, and VisualStudio. One of the key requirements for this project is to have a configuration file containing constants that control various settings such as REST API URLs and environment names. ...

Is it possible to reset the existing localStorage value if we access the same URL on a separate window?

In my app, there are two different user roles: admin and super admin. I am looking to create a new window with a Signup link specifically for registering admins from the super admin dashboard. Is it possible to achieve this functionality in that way? Cu ...

What is the process of converting an Array that is nested within an Object?

I am facing compile errors while attempting to convert an Object containing an Array of Objects. Here is the initial structure: export interface CourseRaw { metaInfo: MetaInfoRaw; gameCode: number; gameText: string; images?: ImageRaw[]; // Having ...

The folder creation in the 'outDir' directory by TSC continues to grow

Hello! Currently, I am engaged in a small TypeScript project where I need to utilize two separate tsconfig.json files, both of which inherit from my main tsconfig.base.json file. Unfortunately, I encountered an issue with the compiler creating unnecessar ...

Issue: This feature cannot be accessed when using the Angular CLI outside of a project workspace during a legacy application migration

Currently working on updating a legacy Angular application where I need to address some vulnerabilities. After updating the node image in the Docker file (which was also updated previously), I encountered the following issues. Unfortunately, I'm havin ...

Angular 2: Issue with view not reflecting changes in array

I am working on a component that involves two arrays: arrayA and arrayB. The elements in arrayB are filtered from arrayA. In the template, I have: <div *ngFor="let elem of arrayB">{{elem.something}}</div> There is also a button: <button ( ...

Retrieve the text content of the <ul> <li> elements following a click on them

Currently, I am able to pass the .innerTXT of any item I click in my list of items. However, when I click on a nested item like statistics -> tests, I want to display the entire path and not just 'tests'. Can someone assist me in resolving this i ...

Using query parameters in Angular to interact with APIs

One scenario involves a child component passing form field data to a parent component after a button press. The challenge arises when needing to pass these fields as query parameters to an API endpoint API GET /valuation/, where approximately 20 optional p ...

Angular app unit tests encountering issues due to Keycloak role-based redirection mechanism

In my Angular application, I needed to redirect users to either /route1 or /route2 based on their role. However, Keycloak only allows for a single route to be specified after logging in (in this case, route1). To solve this routing dilemma, I implemented t ...

What is the best way to transfer information from a model to the screen?

I need assistance with adding a Todo using a model. When I click the Add todo button located at the bottom of the page, it opens the model. I want to be able to add whatever I type in the input field to the list. How can I send the input field data to the ...

Can Angular Material Tabs be customized to have a different style?

I need help styling my mat-tabs to achieve a specific look. Here is the design I am trying to replicate: https://i.stack.imgur.com/tg6XC.png https://i.stack.imgur.com/tth0z.png However, I'm encountering an issue where the white border under the curr ...

Is it possible for me to tap into the component creation process within the Angular Router?

Inspiration struck me when I realized the potential of adding a directive to the component designed for this particular route. It would elevate the functionality by letting me convey crucial information in a more declarative manner. Despite learning that ...

Plugin for managing network connectivity in Ionic framework

In order to check if internet and id connection are available, I need to make a server request. I have implemented the Ionic Native Network Plugin following their official documentation. Here is my code snippet: import { Component } from '@angular/c ...

Ensuring a User has an Image in MySQL Using Angular 6

As part of my development process, I am working on creating a new user and sending their information along with an image to a MySQL database. The process involves sending a user object with form data through the following component.ts file: subscribeUser() ...

What is the best way to transform an array containing double sets of brackets into a single set of brackets?

Is there a way to change the format of this list [[" ", " ", " ", " ", " ", " ", " ", " ", " ", " "]] to look like [" ", " ", " &qu ...

What is the procedure for implementing a RoleGuard in Angular 6?

Is there a way to retrieve the user role from the token? I've managed to fetch the token using the decoding feature of angular2-jwt, but when I try to apply it for accessing the admin route, it returns a value of false. Upon checking with console.lo ...

Error: Module not found - Issue with importing SVG files in NextJS

Currently, I am utilizing the babel plugin inline-react-svg to import inline SVGs in NextJS. Here is a snippet from my .babelrc configuration file: { "presets": ["next/babel"], "plugins": [ "inline-react-svg" ...

"When a class extends another class and utilizes properties within a static property, it essentially becomes

I have been encountering challenges with generics in TypeScript for quite some time now. My current setup is as follows: First, there is a generic class defined as: class Entity { public static schema = {}; } Then, there is a class that extends the ...