Cell Renderer Class
Cell Renderer Class
We recommend that all cell renderers strictly use vanilla JS.
Why?
- Using Angular Components for cell renderers will drastically impact the performance.
- Each cell must bootstrap the Angular component
- Paint performance and frame rate will be negatively impacted - especially when scrolling the grid.
Ok, let's dive into creating a cell renderer using the class-based approach.
The class must implement the ICellRendererComp
interface.
export interface ICellRendererComp<TData = any> {
destroy?(): void;
getGui(): HTMLElement;
init?(params: ICellRendererParams<TData>): AgPromise<void> | void;
refresh(params: ICellRendererParams<TData>): boolean;
}
Let's review each method:
destroy()
is invoked once by the grid when the cell is destroyed. This is an opportunity to perform any clean up to avoid memory leaks. Implementing this method is optional.getGui()
returns theHTMLElement
that is rendered for the cell.init()
is invoked once the cell is created. Implementing this method is optional.refresh()
instructs the cell renderer to refresh, and returnstrue
if successful. If you returnfalse
, then the cell renderer component is destroyed and recreated as necessary.
In our example, we want to add some behavior to our Name
column, namely (ha):
- First, we want to alert the user when they click on the user. This is a bit contrived, but you could imagine we want to perform some sort of action in our application when a user clicks on a cell.
- Second, we want to abbreviate the name value.
To start, let's define the interface for the data that will be provided to the cell renderer.
export interface NameCellRendererData {
id: string;
customer: {
name: string;
};
}
Next, let's define the interface for the click event.
export interface NameCellRendererClickEvent<T, E = Event> {
event: E;
data: T;
}
And, let's define the interface for our cell renderer's custom params
object.
export interface NameCellRendererParams<T> {
click: (event: NameCellRendererClickEvent<T>) => void;
document: Document;
}
Using the NameCellRendererParams
interface we'll create a new Params
type intersection.
type Params<T> = NameCellRendererParams<T> & ICellRendererParams<T, string>;
We're now ready to define the NameCellRenderer
class.
export class NameCellRenderer<T extends NameCellRendererData>
implements ICellRendererComp<T>
{
/** The button element. */
private btnEl: HTMLButtonElement | null = null;
/** Execution context bound function when the button is clicked. */
private handleClick:
| ((this: NameCellRenderer<T>, event: MouseEvent) => void)
| null = null;
/** Store a reference to the params object */
private params: Params<T>;
init(params: Params<T>): void {
this.params = params;
this.setGui();
}
destroy(): void {
if (this.handleClick !== null && this.btnEl !== null) {
this.btnEl.removeEventListener('click', this.handleClick);
}
}
getGui(): HTMLElement {
return this.btnEl!;
}
refresh(params: Params<T>): boolean {
this.params = params;
if (this.btnEl) {
this.btnEl.innerHTML = this.transform();
}
return true;
}
private setGui(): void {
// omitted for brevity
}
}
Let's review the NameCellRenderer
code:
- First, we define the class that implements the
ICellRendererComp
interface. - We'll keep a reference to the
btn
andhandleClick
properties to add and remove the click event listener. - We'll store a reference to the
params
. - As required, we implement the
init()
,getGui()
, andrefresh()
methods. - And, we also implement the
destroy()
method to remove the event listener.