Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular: Pass Component to a Component

I have this small gridComponent:

@Component({
    selector: 'moving-grid',
    templateUrl: './grid.component.html',
    styleUrls: ['./grid.component.css']
})
  export class GridComponent {
     @Input('widgets') extComponents: Array<Component>;
  }

And a second testComponent

@Component({
  selector: 'test',
  template: `
    <div #content>I say hello<li>i</li><li>u</li><button (click)="test()">click me</button> world</div>
  `
})

export class TestComponent {
  @ViewChild('content') content: HTMLElement;

  getContent() {
    return this.content;
  }
  test() {
    console.log("test");
  }
}

Now I'm trying to pass multiple instances of testComponent to the gridComponent. Therefore I have a third Component which looks like this one:

template: `
        <moving-grid [widgets]="[z1,z2]"> 
          <test  class="grid-item-content-001" #z1></test>
          <test  class="grid-item-content-002" #z2></test>
        </moving-grid>
      `

Until this point, everything works like expected. But how can I render the Components from @Input in the gridComponent? My first approach was to declare a @ViewChild in the testComponent and return it with a getContent()-function. But it won't work. Can I use the ng-content directive in some way or is there a better solution?

The GridComponent looks like this. I want to display the templates of a @Input-Component inside one of the black boxes. Is it possible?

Moving-Grid Component

Thanks for any kind of help

like image 490
Draftsman Avatar asked May 12 '17 09:05

Draftsman


People also ask

Can we pass component as input in Angular?

The first step to passing data into an Angular component is to create a custom property to bind to. This is done via “input” binding to pass data from one component to another (typically parent to child). This custom input binding is created via the @Input() decorator!

How do you pass value from component to component?

For passing the data from the child component to the parent component, we have to create a callback function in the parent component and then pass the callback function to the child component as a prop. This callback function will retrieve the data from the child component.

How do you use one component in another component in Angular 7?

This is most frequently used way of sharing data between components. It uses @Input() decorator. You can also use @Output() decorator to event pass to the parent. @ViewChild decorator allows a one component to be injected into another, giving the parent access to its properties and methods.


1 Answers

You should not use an @Input to pass in the components. You can use @ContentChildren for that and an abstract WidgetComponent:

@Component({
    selector: 'moving-grid',
    template: `
      <div class="widget-wrapper">
         <ng-container *ngFor="let widget of widgets">
             <!-- use a ngSwitchCase here for different types-->
             <grid-test-widget [widget]="widget" *ngIf="widget.active && widget.type === 'test'"></grid-widget>
         </ng-container>          
      </div>
    `,
    styleUrls: ['./grid.component.css']
})
export class GridComponent implements AfterContentInit {
     @ContentChildren('widget')
     widgets: QueryList<WidgetComponent>;

     ngAfterContentInit() {
        //your components will be available here
     }
}

The template of your third component will stay the same, but without the [widgets] and an added #widget name:

<moving-grid> 
  <test-widget class="grid-item-content-001" #widget [active]="false"></test>
  <test-widget class="grid-item-content-002" #widget></test>
</moving-grid>

Your TestWidgetComponent which will extend an abstract WidgetComponent :

@Component({
  selector: 'test-widget',
  // ...
})
export class TestWidgetComponent extends WidgetComponent {
    public type: string = 'test';
}

And your WidgetComponent:

@Directive()
export abstract class WidgetComponent {

   @Input()
   public active: boolean;

   public type: string;

}

And you'll have several grid widgets based on the type of the widget:

@Component({
  selector: 'grid-test-widget',
  template: `<div #content>I say hello<li>i</li><li>u</li><button (click)="test()">click me</button> world</div>`
})
export class GridTestWidgetComponent{}
    
like image 168
Poul Kruijt Avatar answered Sep 29 '22 12:09

Poul Kruijt