Enhance your Angular Grid reports with Formatted values and Links

Advanced cell formatting in ag-Grid

Michael Karén
Oct 31, 2018 · 5 min read
Image for post
Image for post
Photo by Mika Baumeister on Unsplash

All that studying just to become a spreadsheet engineer…

In this article, I explain how to do some Wow, that sounds awesome, but what do I mean by all these fancy words?

First of all, we need to have some for how we . For example, if we always name our car columns ‘car’, then we can look for that name in our code.

And when we have found that car column we can add the code to our column definitions in the grid. So this means that we could run different reports in our grid. And for all reports where we find this car column we can format the cells.

The end product will be the grid below where we have some nice formatting of dates and numbers. Above the grid, we have a router outlet. When links are clicked we route to it and send the text from the cell via route parameters.

Image for post
Image for post

If you are new to ag-Grid you can check out Get started with Angular Grid in 5 minutes and Learn to customize Angular grid in less than 10 minutes by Max, Wizard of the Web.

I will not be explaining much of the topics that are already covered in those articles but will jump right into the next level of cell formatting. If you want to play with the code along the way, I prepared a StackBlitz with the finished code.

Pipe Setup

In my article Custom Angular Pipes and Dynamic Locale, I showed how to create custom pipes for formatting your dates and numbers.

We can use them in our component by importing them from the library we created in that article and then injecting them in the constructor:

import { LocalDatePipe, LocalNumberPipe } from 'lib-shared';constructor(private dateFormatter: LocalDatePipe, private numberFormatter: LocalNumberPipe)`

Similarly, we can use the standard Angular pipes:

import { DatePipe, DecimalPipe } from '@angular/common';constructor(private dateFormatter: DatePipe, private numberFormatter: DecimalPipe) {}

These pipes will work the same as the custom ones if you don’t need the extra locality functionality that comes with them.

Since we are injecting the pipes in the constructor, we need to add them to in the module file so that they become injectable.


By naming all our date columns ‘xxxDate,’ we can easily discover them. In our example, the column is named ‘releaseDate’. When we know which columns contain dates we can format them with the pipe transform method.

From the docs:

“A valueFormatter allows you to format or transform the value for display purposes.”

A value formatter is just what we need. We look for all columns that end with ‘Date’ and add the date pipe to the valueFormatter property:

ColumnDefs and RowData

We can use the code from the last paragraph to start building on our method to define the columns: setColumns(columns: string[])

As you can see we need to have the columns before we can run this method. And to have the columns in a dynamic setting, we have to fetch the data first.

How can we extract the column names from an array of unknown type?

You could, for example, take the first object from the array and get the column names with Object.keys(). It returns an array of a given object’s property names

const columns = Object.keys(data[0]);

In our example, we have hard-coded our data and column names. We run this code in the constructor.

const columns = ['car', 'bus', 'releaseDate', 'price'];


Find out if there are any conventions in the reports for numbers. If not then maybe you can create some. In our example, we look for the ‘price’ column.

When we know which column names to look for we can use our number formatter to format these numbers as we like. Again we use valueFormatter:

(params) => this.numberFormatter.transform(params.value, '1.2-2'),

We can also set the column definition type to numericColumn, which aligns the column header and contents to the right.

Like this blog post? Share it on Twitter! 🐦

Routing Setup

Let’s set up a basic routing for our app. Add a router outlet to the template that holds our grid. It acts as a placeholder where the router should display our components.

<ag-grid-angular [rowData]="rowData" [columnDefs]="columnDefs">

Next, we can set up the routes where we setup route parameters to our components that are going to be the text from the cells.

const appRoutes: Routes = [
{ path: 'car/:car', component: CarComponent },
{ path: 'bus/:bus', component: BusComponent }

And lastly, we create a simple component where we subscribe to the route parameters and show them in our template.

Links by Cell Renderers

I want to use the text in cells for specific columns as links. To achieve this valueFormatter is not enough. Instead, we need to create a component for our ag-Grid cells.

From the docs:

“By default the grid will create the cell values using simple text. If you want more complex HTML inside the cells then this is achieved using cell renderers.”

For re-usability, we can make a component that passes a link in as an argument. We can do this with cellRendererParams.

We want our column definition to look like this:

cellRendererFramework: MyLinkRendererComponent,
cellRendererParams: {
inRouterLink: '/yourlinkhere',

In our component, we need to implement AgRendererComponent. With it comes the agInit() and refresh() methods. In our refresh, we return false which means your component will be destroyed and recreated if the underlying data changes.

Then there is the template. We can implement an Angular RouterLink where ‘params.value’ is the value from the cell:

<a [routerLink]="[params.inRouterLink, params.value]">

I once ran into some issues where the link was not working, and I had to jump start the Angular change detection. If you run into that kind of problems and like I can’t figure out why its happening you can check my work-around on stack overflow.

But hopefully you won’t have to monkey patch anything, and the code will look like this:

We have to add the renderer to the entry components for the module.

Column Definitions

Now that we have our cell renderer we can set it up in the column definitions.

And that’s it! If you have any other good ideas on how we can enhance our grid, please comment below.

Call to Action

I always enjoy feedback so please 👏, 📝 and tweet 🐦.
Follow me on Twitter and Medium for blog updates.

Join the and who use ag-Grid to provide the best possible experience to their users.


We are ag-Grid and our mission is to build the best…

Thanks to Max Koretskyi

Michael Karén

Written by

Angular by day, React by night. Senior Consultant jProfessionals. Educator wannabe. ngVikings organizer.



We are ag-Grid and our mission is to build the best datagrid in the world

Michael Karén

Written by

Angular by day, React by night. Senior Consultant jProfessionals. Educator wannabe. ngVikings organizer.



We are ag-Grid and our mission is to build the best datagrid in the world

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app