AG Grid : gridReady event not triggered when loading grid in a component via ComponentFactoryResolver
Asked Answered
P

3

5

On my Angular 10 app, I'm loading through the component factory resolver a component containing an AG Grid.

When I trigger the factory resolver through a button, everything works fine. The Grid is displayed and the gridReady event is fired correctly.

However if I trigger the component factory resolver through through ngOnInit() or ngAfterViewInit() etc., the gridReady event is not triggered and the grid is not displayed.

I tried to use the ChangeDetectorRef service to force a change detection, but that didn't change anything.

This is the code for the component factory resolver:

export class PlannerComponent implements OnInit {
  @ViewChild('ordersContainer', {read: ViewContainerRef}) container: ViewContainerRef;
  public orders = [];

  constructor(
    private componentFactoryResolver: ComponentFactoryResolver,
    private httpClient: HttpClient
  ) { }

  ngOnInit(): void {
    this.loadOpenOrders();
  }

  loadOpenOrders() {
    this.httpClient.get('/orders')
      .pipe(map((result: any) => {
        const orders = result._embedded.orders;
        orders.forEach((function (order) {
          this.addOrder();
        }).bind(this))
      }))
      .subscribe()
  }

  onGridReady(params) {
    this.gridApi       = params.api;
    this.gridColumnApi = params.columnApi;
    this.gridApi.sizeColumnsToFit();
  }

  addOrder() {
    // Create component dynamically inside the ng-template
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(OrderComponent);
    const newOrder         = this.container.createComponent(componentFactory);

    // Push the component so that we can keep track of which components are created
    this.orders.push(newOrder);
  }
}

In the view, the component is loaded like this:

<div class="container">
  <div class="row">
    <div class="col-6">
      <div class="card card-custom gutter-b">
        <ag-grid-angular
          style="width: 100%; height: 600px;"
          class="ag-theme-alpine"
          [rowData]="ordersToPlan"
          [columnDefs]="columnDefs"
          [rowSelection]="rowSelectionType"
          (gridReady)="onGridReady($event)"   <==== Only triggered through button click, but not on ngOnInit()
          [animateRows]="true"
        >
        </ag-grid-angular>
      </div>
    </div>
    <div class="col-6">
      <button class="btn btn-success mb-5" (click)="addOrder()">Add a new Order</button>
      <div>
        <ng-template #ordersContainer>
        </ng-template>
      </div>
    </div>
  </div>
</div>

Any help is appreciated :-)

Premise answered 10/11, 2020 at 15:13 Comment(0)
P
4

I finally found the problem. I needed to enforce change detection, but in the sub-component (the one I'm loading through the component Factory resolver).

In order.component.ts :

constructor(
    private cd: ChangeDetectorRef
  ) { }

...

setTransport(transport: Transport): void {
    ...
    this.cd.detectChanges();
  }

A big thanks to everyone who tried to solve this!

Premise answered 24/11, 2020 at 12:30 Comment(0)
B
2

I see issue at one place in your code.

Instead of calling addOrders within pipe operator, it should have been done in the subscribe part of the get call.

  loadOpenOrders() {
    this.httpClient.get('/orders')
      .subscribe((result: any) => {
        const orders = result._embedded.orders;
        orders.forEach(order => {
          this.addOrder();
        });
      });
  }

Why I think this could help? - maybe change detection cycle might have something to do with subscribe of rxjs Observable; and as your code is doing all those stuffs before/outside subscribe, it might be getting missed by the cycle.

Since I could not these code as comment, posting this as answer. Let me know if this works. Comment any error you get / observation you have. If you could provide any working example (plunk/stackblitz), will be able to help you out quickly.

Will delete this answer if its not helpful.

Blenheim answered 20/11, 2020 at 4:57 Comment(0)
U
2

Try this:

Convert

public orders = [];

into an Observable:

private ordersBS = new BehaviourSubject<any[]>([]);
public orders$ = this.ordersBS.asObservable();

HTML:

[rowData]="orders$ | async"

When adding an order:

this.ordersBS.next(newOrder);

This way agGrid will always be listening to the orders$ observable.

onGridReady function is supposed to be called only once.

Undecided answered 23/11, 2020 at 14:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.