Error: projects/custom-lib/src/lib/components/accordion/accordion.component.html:1:1 - error NG8001: 'ngb-accordion' is not a known element

Viewed 307

So, I have created an Angular Library Project that I am consuming in my application source without publishing (as of now).

The reason to create this library is to setup some common components which will be created by skinning (changing scss) ng-bootstrap library and then consumed in various pages of the application.

So far, I have successfully skinned a few components already where no custom tags were used i.e. Tabs, Datepickers etc. and it all worked as expected and I could export these as part of my Library Level Module which I later imported where needed in my app.

Now, I am planning to also skin the ng-accordion but it is different from the other provided components i.e. it has custom tags <ngb-accordion> , <ngb-panel> etc. using which gives me the following error (while building),

Error: projects/custom-lib/src/lib/components/accordion/custom-lib-accordion.component.html:1:1 - error NG8001: 'ngb-accordion' is not a known element: 
1. If 'ngb-accordion' is an Angular component, then verify that it is part of this module. 
2. If 'ngb-accordion' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.

What I have tried ?

I assumed the reason for this error as the custom-tag being used which during the library build angular can't understand and ending up throwing this. So, I have added the @angular/elements package to my project and specified this tag in the customElements, so as to make angular aware of this custom tag which is coming from ng-bootstrap. But the build still fails with the same error.

Following is my code snippet,

component.html

<ngb-accordion #acc="ngbAccordion" class="custom-accordion" (panelChange)="changeArrow($event,acc)"> 
  <ngb-panel *ngFor="let faq of faqs" id="faq-{{faq.id}}"> 
    <ng-template ngbPanelHeader> 
      <h5 class="custom-accordion__title_text">{{ faq.question }}</h5> 
      <div class="custom-accordion__title_button"> 
        <button class="btn btn-link p-0" ngbPanelToggle> 
          <ng-container *ngIf="selectedPanelId.includes(faq.id)"> 
            <ng-container *ngIf="closeOpenedPanel"> 
              <i class="custom-icon custom-down-icon"></i> 
            </ng-container> 
            <ng-container *ngIf="!closeOpenedPanel"> 
              <i class="custom-icon custom-up-icon"></i> 
            </ng-container> 
          </ng-container> 
          <ng-container *ngIf="!selectedPanelId.includes(faq.id)"> 
            <i class="custom-icon custom-down-icon"></i> 
          </ng-container> 
        </button> 
      </div> 
    </ng-template> 
    <ng-template ngbPanelContent> {{faq.answer}} </ng-template> 
  </ngb-panel> 
</ngb-accordion>

component.ts

import { Component, Input } from '@angular/core'; 
import { NgbPanelChangeEvent } from '@ng-bootstrap/ng-bootstrap'; 
 
export interface FAQ { 
  id: string; 
  question: string; 
  answer: string; 
} 
 
@Component({ 
  selector: 'custom-accordion', 
  templateUrl: './custom-accordion.component.html', 
  styles: [` 
      @import "variables/variables"; 
 
      @include custom-media(">sm") { 
      ::ng-deep .card { 
        .card-header { 
          justify-content: space-between; 
          padding: 1.5rem 0; 
          margin-bottom: 0; 
        } 
        .card-body { 
          padding: 0; 
        } 
        .collapse { 
          &.show { 
            font-size: 1rem; 
            padding: 0 0 1.5rem 0; 
            margin: 0; 
            max-width: 70%; 
          } 
        } 
      } 
 
      &__title_text { 
        font-size: 0.875rem; 
        max-width: 70%; 
        padding-right: 0; 
      } 
     } 
  `], 
}) 
export class CustomAccordionComponent { 
  @Input() public faqs: FAQ[]; 
  closeOpenedPanel: boolean = false; 
  selectedPanelId: string = 'ngb-panel-'; 
 
  constructor() { } 
 
  /** 
   * To change the accordion arrow direction 
   * we check the current active-panel (clicked/interacted) 
   * first and then also check whether the panel is currently open. 
   */ 
  changeArrow($event: NgbPanelChangeEvent, acc: any) { 
    this.selectedPanelId = $event.panelId; 
    if (acc.isExpanded(this.selectedPanelId)) { 
      this.closeOpenedPanel = true; 
    } else { 
      this.closeOpenedPanel = false; 
    } 
  } 
}

module.ts - This will export the custom component created above.

import { Injector, NgModule } from '@angular/core'; 
import { createCustomElement } from '@angular/elements'; 
import { NgbAccordionModule, NgbAccordion, NgbAccordionConfig, NgbPanel } from '@ng-bootstrap/ng-bootstrap'; 
import { CustomAccordionComponent } from './custom-accordion.component'; 
import { CommonModule } from '@angular/common'; 
import { BrowserModule } from '@angular/platform-browser'; 
 
 
@NgModule({ 
    imports: [CommonModule, BrowserModule, NgbAccordionModule], 
    declarations: [CustomAccordionComponent], 
    entryComponents: [CustomAccordionComponent], 
}) 
export class CustomAccordionModule { 
    constructor(private injector: Injector) { } 
 
    public ngDoBootstrap(): void { 
 
        const c1: any = createCustomElement(CustomAccordionComponent , { injector: this.injector }); 
 
        if (!customElements.get('ngb-accordion')) { 
            customElements.define('ngb-accordion', c1); 
        } 
 
    } 
}

home.page.html - usage.

<custom-accordion [faqs]="faqs"></custom-accordion>

home.module.ts

@NgModule({ 
  imports: [ 
    CommonModule, 
    CustomModule, 
    ComponentsModule, 
    PageRoutingModule, 
    NgbModule, 
    ReactiveFormsModule, 
    FormsModule, 
  ], 
  declarations: [...], 
  schemas: [CUSTOM_ELEMENTS_SCHEMA] 
}) 
export class HomeModule { }

Not sure, what is that I am missing. The same code works just fine when used right away in the application. Therefore, I am sure it is this custom ngb-accordion tag that is causing this. Please suggest me a direction to get around this, if you can point it out.

1 Answers

As you're creating a custom element (web component), angular is just not aware that this is a component you want to use.

In the module where you use the component you'll need to add CUSTOM_ELEMENTS_SCHEMA as following:

@NgModule({
// imports, exports, etc
schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
})

Probably you're also lacking to add this component in the exports-array in your declaring module

Related