0

In angular slickgrid, I am using custom angular component to display the user info. Is possible to display custom angular tag by using custom formatter. Here i shared my code snippet.

export const CspfmAuditInfoFormatter: Formatter = (row: number, cell: number, value: any, columnDef: any, dataContext: any, grid: any) => {
  return `<ion-buttons>
        <cspfm-audit-info [setIcon]="ios-information-circle-outline" [setIconClass]="" [setInfo]="${dataContext}"></cspfm-audit-info>
    </ion-buttons>`
}; 

cspfm-audit-info is my own angular component to display the data audit information. I want to display the cspfm-audit-info.


Software Version

Angular : 7.3.5

Angular-Slickgrid : 2.19.0

TypeScript : 3.1.6

Operating System : Windows 10

Node : 10.16.3

NPM : 6.9.0

Nelson Gnanaraj
  • 176
  • 1
  • 13

1 Answers1

1

That was asked multiple times in Angular-Slickgrid, see these issues #7 and #148 and this other Stack Overflow Question How to render custom angular component instantly in angular slickgrid

The short answer is NO you cannot do that with a Custom Formatter, but you can do it with asyncPostRenderer and here's the Wiki - Using Angular Component with asyncPostRenderer and here's the Example 22 with a sample.

BUT using asyncPostRenderer has lots of disadvantage and I wrote them in the Wiki, here's the main part:

First of... Why can't we use Angular Component with Customer Formatters? Because of how Angular is built, it requires a full cycle for the component to be rendered with data, however SlickGrid Formatter requires only string output and it must be right away (synchronous) and Angular Component can only be returned in an async fashion (you could return it right away but the data won't be populated). That is the reason that it's not doable with a Formatter, however SlickGrid offers asyncPostRender which is similar to a Formatter and works in an async fashion. So that works, but it has some drawback, since it's async, it is slightly slower to render (you might visually see it rendering on the screen). All that to say, regular Formatters with jQuery and/or HTML is still the preferred way (at least to me)... but hey, if you really wish to use Angular Component, well then it's possible, just remember it's async though and slightly slower to render.

Then I finish with this

A Better Solution is to use Custom Formatters as much as possible because using an Angular Components with asyncPostRender are SLOW (you are warned). They are slow because they require a full cycle, cannot be cached and are rendered after each rows are rendered (because of their asynchronous nature), while Custom Formatters are rendered at the same time as the row itself since they are synchronous in nature.

If you really wish to give it a try (I'm nearly sure that you'll change your mind after trying it), here's the code

import {
  AngularGridInstance,
  AngularUtilService,
} from 'angular-slickgrid';

export class MyComponent {
  constructor(private angularUtilService: AngularUtilService){ }
  
  initGrid() {
    this.columnDefinitions = [
      {
        id: 'assignee2',
        name: 'Assignee with Angular Component',
        field: 'assignee',
        minWidth: 100,
        filterable: true,
        sortable: true,
        filter: {
          model: new CustomAngularComponentFilter(), // create a new instance to make each Filter independent from each other
          collection: this.assignees,
          params: {
            component: FilterNgSelectComponent,
          }
        },
        queryFieldFilter: 'assignee.id', // for a complex object it's important to tell the Filter which field to query and our CustomAngularComponentFilter returns the "id" property
        queryFieldSorter: 'assignee.name',

        // loading formatter, text to display while Post Render gets processed
        formatter: () => '...',

        // to load an Angular Component, you cannot use a Formatter since Angular needs at least 1 cycle to render everything
        // you can use a PostRenderer but you will visually see the data appearing,
        // which is why it's still better to use regular Formatter (with jQuery if need be) instead of Angular Component
        asyncPostRender: this.renderAngularComponent.bind(this),
        params: {
          component: CustomTitleFormatterComponent,
          angularUtilService: this.angularUtilService,
          complexFieldLabel: 'assignee.name' // for the exportCustomFormatter
        },
        exportCustomFormatter: Formatters.complexObject,
      }
    ];

    this.gridOptions = {
      enableAsyncPostRender: true, // for the Angular PostRenderer, don't forget to enable it
      asyncPostRenderDelay: 0,    // also make sure to remove any delay to render it
    };
  }

  renderAngularComponent(cellNode: HTMLElement, row: number, dataContext: any, colDef: Column) {
    if (colDef.params.component) {
      const componentOutput = this.angularUtilService.createAngularComponent(colDef.params.component);
      Object.assign(componentOutput.componentRef.instance, { item: dataContext });

      // use a delay to make sure Angular ran at least a full cycle and make sure it finished rendering the Component
      setTimeout(() => $(cellNode).empty().html(componentOutput.domElement));
    }
  }
}

Conclusion

Final Word, it's slow and I never personally use, but hey it's doable if you wish to have a slow rendering... my users certainly don't want that and so I never use them.

ghiscoding
  • 12,308
  • 6
  • 69
  • 112
  • Thanks for your information @ghiscoding. But I have already tried asyncPostRender in my application. The rendering of angular component gives some bad user experience. So that i am trying to display my angular components by custom formatter. – Nelson Gnanaraj Jul 22 '20 at 08:45
  • Well I already said that is the **only** way to do it and I explained why (mainly because Angular requires a full cycle to render), a Custom Formatter requires a string output right away (sync) and Angular will never give you that (async)... unless Angular has some kind of magic to do it in a sync way but I really doubt it. You might not like the answer but that is the only possible way to do it and that is why I never use Angular tags – ghiscoding Jul 22 '20 at 12:15
  • BTW, if you ever find a way to do it in a Custom Formatter then please let me, I'd be happy to update my Wiki and demo with such code. I don't think it's possible, but someone might have found a way... if so I'd like to know. – ghiscoding Jul 22 '20 at 16:44
  • Sure @ghiscoding – Nelson Gnanaraj Jul 22 '20 at 16:47