I am trying to use ag-grid in an Angular 2 application. Since I use endless scrolling and filtering on the server side, I want basically all of my columns in the grid to have custom filters that can then be passed to the server on which the filtering will actually be performed . Although ag-grid has a relatively straightforward interface for configuring these custom filters, the ag-grid page in the ag-grid documentation notes that ag-grid uses Angular 1 compilation, and with Angular 2 it does not support compilation after application startup, none of the custom components in the grid (custom filters, cells, rows, etc.) Does not support any of the Angular 2 functions (for example, two-way data binding, etc.).
So, I was looking for a way for Angular 2 to dynamically load a component into a DOM element that ag-grid inserts into a filter popup. I looked at both DynamicComponentLoader (which is deprecated) and several use cases for ComponentResolver. Once I have a ComponentResolver, I can call resolveComponent to get the ComponentFactory, and then I can use @ViewChild to get the ViewContainerRef and call createComponent in this ViewContainerRef to create my new component. However, this does not help me with the grid, because @ViewChild will not find the element dynamically added to the DOM directly, as the ag-grid does.
Alternatively, when I have a ComponentResolver component and the resolveComponent method is called to get the ComponentFactory, I can call create on componentFactory and pass it the injector from my ViewContainerRef and a string tag for the element that I want the component to be inserted into and that "seems "works, but the component does not display correctly. I get similar behavior if I use DynamicComponentLoader (i.e. the Component does not display as expected).
Is there any acceptable way to load an Angular 2 component within a specific element in the DOM?
Below is the code to illustrate the problem that I based on Angular 2 quickstart:
app.component.ts:
import { Component, ViewChild } from '@angular/core'; import { ComponentResolver, ViewContainerRef } from '@angular/core'; import { DynComponent } from './dyn.component'; @Component({ selector: 'my-app', template: ` <h1>My test Angular 2 App</h1> <input type="text" class="form-control" required [(ngModel)]="name" > TODO: remove this: {{name}} <p> </p> <div #insertPoint> <button (click)="createDynamicComponent()">Create The Dynamic Component</button> Inserting a new component below this. </div>` }) export class AppComponent { name: string; @ViewChild('insertPoint', {read: ViewContainerRef}) compInsertPoint: ViewContainerRef; constructor(private componentResolver: ComponentResolver){} createDynamicComponent(){ console.log("Creating new Component.");
dyn.component.ts
import { Component } from '@angular/core'; @Component({ selector: 'dyn-app', template: ` <h1>My test Angular 2 App</h1> <input type="text" class="form-control" required [(ngModel)]="name" > TODO: remove this: {{name}}` }) export class DynComponent { name: string; }
HTML result after one button click in app.component (note the inconsistency in input type = "text" and the following simple text starting with "TODO:")
<my-app> <h1>My test Angular 2 App</h1> <input class="form-control ng-untouched ng-pristine ng-invalid" required="" type="text"> TODO: remove this: <p> </p> <div> <button>Create The Dynamic Component</button> Inserting a new component below this. <span> <div id="dynCompDiv"> <h1>My test Angular 2 App</h1> <input class="form-control" required="" type="text"> </div> </span> </div> </my-app>
Update : here is Plunker with this example: Angular2 Dynamic Component
Update 2 . A bit more information on the above comment that I get similar behavior using DynamicComponentLoader. If I read the Angular code correctly, DynamicComponentLoader basically does the same thing as I do above. It resolves the component to get a ComponentFactory, and then uses the create method in the factory. So this kind of behavior makes sense.
Update 3 . Updated Plunker to work again. Updated Plunker