0

I have a simple component where I've placed multiple buttons and I want to show those buttons in another component (functionality of buttons also comes from my buttons component) but i get this error in terminal

ERROR NullInjectorError: R3InjectorError(HelpdeskModule)[ButtonsComponent -> ButtonsComponent -> ButtonsComponent -> ButtonsComponent]: 
  NullInjectorError: No provider for ButtonsComponent!

Code

buttons.component.html

<div class="mb-3">
  <nz-button-group>
      <button nz-button nzType="primary" (click)="buttonClick('create button')" class="ant-btn ant-btn-primary ant-btn-lg"><i nz-icon nzType="download"></i>Create New</button>
  </nz-button-group>
</div>

list.component.ts (this is where i want to show those components)

  import { ButtonsComponent } from 'src/app/components/app/layout/buttons/buttons.component';

  constructor(
    private buttons: ButtonsComponent,
  ) { }

And list.component.html

// I am uncertain about this part to be correct at all!
{{buttons}}

Any idea?

Update

I've added Injectable to my buttons component like this: (just playing around to get them printed )

import { Component, OnInit, Injectable } from '@angular/core';
import { NzNotificationService } from 'ng-zorro-antd'


@Component({
  selector: 'app-buttons',
  templateUrl: './buttons.component.html',
  styleUrls: ['./buttons.component.scss']
})

@Injectable({
  providedIn: 'root'
})

export class ButtonsComponent implements OnInit {
  //
}

and now I'm getting this error

ERROR TypeError: Invalid attempt to spread non-iterable instance.
In order to be iterable, non-array objects must have a [Symbol.iterator]() method.

3 Answers 3

2

First thing, inside list.component.html just place html like below

<app-buttons></app-buttons>

And then you want to call method of of ButtonsComponent, use it as a dependency, you have to keep it in providers array first.

providers: [
  ...,
  ButtonsComponent,
  ...
]

But as I look through your updated question, you don't have to inject the component inside constructor, rather you can use ViewChild.

@ViewChild('buttons', { static: false, read: ViewContainerRef })
buttons: ButtonsComponent;

list.component.html

<app-buttons #buttons></app-buttons>

Stackblitz Demo

Sign up to request clarification or add additional context in comments.

11 Comments

Hi, where should I place this viewChild? in my buttons component or list component? and ViewContainerRef if imported from?
@mafortis I'm little unsure now after your question update. What exactly you want to do. Just you to render the app-buttons component inside list.component.html and call its method from parent component?
Yes I want to print them in my list.component.html and no, for now there will be nothing dynamically passed from list.component.html to buttons.component.ts it all static now
it returns ERROR TypeError: Invalid attempt to spread non-iterable instance. In order to be iterable, non-array objects must have a [Symbol.iterator]() method.
sorry i didn't know that you've updated your answer :/ first thing tomorrow morning I will test your update and let you know.
|
0

Using ComponentFactoryResolver in Angular to handle dynamic loader for multiple components:

Here is sample code:

import {
    Component,
    ComponentFactory,
    ComponentRef,
    ComponentFactoryResolver,
    ViewContainerRef,
    ViewChild
} from '@angular/core'
import { AComponent } from './a.component';
import { BComponent } from './b.component';

@Component({
    selector: 'modal-resolver',
    template: `
        <template #modalContainer></template>
    `,
})
export class ModalResolver {
    @ViewChild("modalContainer", { read: ViewContainerRef }) container;
    @Input() name;
    componentRef: ComponentRef;

    listComponent: {
        'modalA': AComponent,
        'modalB': BComponent
    }

    constructor(private resolver: ComponentFactoryResolver) { }

    ngOnInit() {
        this.loadComponent(this.name);
    }
    loadComponent(type) {
        this.container.clear();
        const factory: ComponentFactory = this.resolver.resolveComponentFactory(this.listComponent[this.name]);

        this.componentRef = this.container.createComponent(factory);

        this.componentRef.instance.type = type;

        this.componentRef.instance.output.subscribe(event => console.log(event));

    }

    ngOnDestroy() {
        this.componentRef.destroy();
    }
}

Then you use it:

<modal-resolver name="modalA"></modal-resolver>

2 Comments

Not sure, when OP asked to load component dynamically?
ERROR TypeError: this.listComponent is undefined
0

  printComponent(elementId: any, scape: any = 'landscape') {
    const originalContents = document.body.innerHTML;
    const printContents = document.getElementById(elementId).innerHTML;
    const css = '@page { size: ' + scape + '; }';
    const head = document.head || document.getElementsByTagName('head')[0];
    const style: any = document.createElement('style');

    style.type = 'text/css';
    style.media = 'print';

    if (style.styleSheet) {
      style.styleSheet.cssText = css;
    } else {
      style.appendChild(document.createTextNode(css));
    }

    head.appendChild(style);

    document.body.innerHTML = printContents;

    window.print();

    document.body.innerHTML = originalContents;

    window.location.reload();
  }
<div>
  <h3>Page d'impression des états</h3>
  <button
    nbButton size="tiny" outline status="warning" class="align-middle"
    (click)="printComponent('componentId')"
  >
    <nb-icon icon="print-outline"></nb-icon>
    IMPRIMER
  </button>
  <div id="usersId">
    <table class="table" id="componentId">
      <thead>
      <tr>
        <th scope="col">Class</th>
        <th scope="col">Heading</th>
        <th scope="col">Heading</th>
      </tr>
      </thead>
      <tbody>
      <ng-container *ngFor="let i of [].constructor(100)">
        <tr>
          <th scope="row">Default</th>
          <td>Cell</td>
          <td>Cell</td>
        </tr>

        <tr class="table-primary">
          <th scope="row">Primary</th>
          <td>Cell</td>
          <td>Cell</td>
        </tr>
        <tr class="table-secondary">
          <th scope="row">Secondary</th>
          <td>Cell</td>
          <td>Cell</td>
        </tr>
        <tr class="table-success">
          <th scope="row">Success</th>
          <td>Cell</td>
          <td>Cell</td>
        </tr>
        <tr class="table-danger">
          <th scope="row">Danger</th>
          <td>Cell</td>
          <td>Cell</td>
        </tr>
        <tr class="table-warning">
          <th scope="row">Warning</th>
          <td>Cell</td>
          <td>Cell</td>
        </tr>
        <tr class="table-info">
          <th scope="row">Info</th>
          <td>Cell</td>
          <td>Cell</td>
        </tr>
        <tr class="table-light">
          <th scope="row">Light</th>
          <td>Cell</td>
          <td>Cell</td>
        </tr>
        <tr class="table-dark">
          <th scope="row">Dark</th>
          <td>Cell</td>
          <td>Cell</td>
        </tr>
      </ng-container>
      </tbody>
    </table>
  </div>
</div>

1 Comment

Any explanation to back this code up please?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.