I am building angular 4 app with ag-grid and I am having an issue with trying to figure out how to put a link in the cell. Can anybody help me with that issue? Thanks
-
did you ever find the solution for this? Would you be willing to post? Looks like the only answer below is for javascript, looks like you need typescript solution.. – Judy007 May 31 '18 at 16:22
-
This helped me: https://stackoverflow.com/questions/45218532/clickable-url-value-in-ag-grid-with-react#comment123766268_45231951 – Ryan Nov 18 '21 at 03:40
9 Answers
Please check this demo
cellRenderer: function(params) {
return '<a href="https://www.google.com" target="_blank" rel="noopener">'+ params.value+'</a>'
}
In this demo, the cell value for the column 'city' is a hyperlink.

- 6,247
- 2
- 36
- 24

- 484
- 5
- 13
-
-
angular 4 uses typescript, the solution you provide above is for javascript. – Judy007 May 31 '18 at 16:22
-
I really don’t understand why people downvote for no reason ! My answer is from my experience with ag- grid, don’t know why it needed to be downvoted! – gunnerwhocodes May 31 '18 at 20:13
-
1This is a good answer, perfectly valid for Angular. If you inject Router into your component, it has functions on it that will allow you to construct the URL for a route link just like you would a routerLink attribute in a template, or sometimes the route link is easy enough just to build without any help as in shr's answer below. Something like building a reusable RouterLinkRendererComponent as also suggested below works too, but not necessary. – reads0520 Nov 07 '18 at 22:06
I struggled with this the other day and it was bit more complex than I first thought. I ended up with creating a renderer component to which I send in the link and that needed a bit on NgZone magic to work all the way. You can use it in your column definition like this:
cellRendererFramework: RouterLinkRendererComponent,
cellRendererParams: {
inRouterLink: '/yourlinkhere',
}
Component where inRouterLink is the link that you send in and params.value is the cell value. That means that you can route to your angular route that could look something like 'yourlink/:id'. You could also simplify this a bit if you don't want a more generic solution by not sending in the link and just hard coding the link in the template and not using the cellRendererParams.
import { Component, NgZone } from '@angular/core';
import { Router } from '@angular/router';
import { AgRendererComponent } from 'ag-grid-angular';
@Component({
template: '<a [routerLink]="[params.inRouterLink,params.value]" (click)="navigate(params.inRouterLink)">{{params.value}}</a>'
})
export class RouterLinkRendererComponent implements AgRendererComponent {
params: any;
constructor(
private ngZone: NgZone,
private router: Router) { }
agInit(params: any): void {
this.params = params;
}
refresh(params: any): boolean {
return false;
}
// This was needed to make the link work correctly
navigate(link) {
this.ngZone.run(() => {
this.router.navigate([link, this.params.value]);
});
}
}
And register it in
@NgModule({
imports: [
AgGridModule.withComponents([
RouterLinkRendererComponent,
])
],
})
UPDATE: I have written a blog post about this: https://medium.com/ag-grid/enhance-your-angular-grid-reports-with-formatted-values-and-links-34fa57ca2952

- 6,247
- 2
- 36
- 24

- 1,105
- 9
- 13
-
1Thank you for this answer. I was having an issue when navigating that the target component was loading a blank template without making any calls to ngOnInit. I had not realized that ag-grid executes CellRenderFrameworks outside the angular environment. NgZone to the rescue. – Slowbie Jul 24 '18 at 22:54
-
2Important! Don't forget to add the component `RouterLinkRendererComponent` to a module as entryComponent. `entryComponents: [ RouterLinkRendererComponent ]`. Otherwise, you will recieve lots of ag-grid render errors. – hastrb Apr 19 '19 at 10:37
-
Great solution. I have an improved version, for those who think you need a bit more flexibility, take a look of my version https://stackoverflow.com/a/62207311/2736817 – tom10271 Jun 05 '20 at 02:49
This is a bit dated, but it may help someone. The solution with typescript on Angular 5 is similar to what C.O.G has suggested. In the component's typescript file, the column definition can contain a custom cell rendering function.
columnDefs = [
{headerName: 'Client', field: 'clientName' },
{headerName: 'Invoice Number', field: 'invoiceNumber',
cellRenderer: (invNum) =>
`<a href="/invoice/${invNum.value}" >${invNum.value}</a>` },
];
The lambda function is called while rendering the cell. The 'value' of the parameter that gets passed is what you can use to generate custom rendering.

- 6,247
- 2
- 36
- 24

- 875
- 10
- 20
-
2Using href seems to work fine, but the problem with this is that it reloads entire angular app.. (Atleast it does for me?) routerLink doesn't seem to work. – Marius Nov 19 '18 at 14:13
-
@Marius, did you setup the route paths for the links used in href ? If routes are setup properly, it shouldn't reload the entire angular app. – shr Dec 04 '18 at 12:16
-
`href` and `routerLink` are completely different stories... I would create a simple component to wrap with a routerLink angular in the template and then add this component to columnDefs as a column. It is almost identical what Michael suggested above. – hastrb Apr 19 '19 at 10:02
Inspired by @Michael Karén
This is a improved version that is more flexible.
- We can set what text to display in link
- We can pass more than 2 routerLink parameters
- Resolve routerLink according to data
- Support target
- Display text only if link is not applicable
- And more if you wanted to add, just further edit this component
import { Component } from '@angular/core';
import { ICellRendererAngularComp } from 'ag-grid-angular';
export interface IRouterLinkRendererComponentOptions {
routerLinkParams?: any[];
linkDescription?: string;
textOnly?: string;
target?: string;
}
@Component({
template: `
<a *ngIf="params.textOnly == null; else textOnlyBlock"
[routerLink]="params.routerLinkParams"
[target]="params.target ? params.target : '_self'"
>
{{ params.linkDescription }}
</a>
<ng-template #textOnlyBlock>
{{ params.textOnly }}
</ng-template>
`
})
export class RouterLinkRendererComponent implements ICellRendererAngularComp {
params: IRouterLinkRendererComponentOptions;
agInit(params: any): void {
this.params = params.routerLinkRendererComponentOptions(params);
}
refresh(params: any): boolean {
return true;
}
}
So that we can dynamically resolve parameters and return text only if wanted in column definition by
{
...
cellRendererFramework: RouterLinkRendererComponent,
cellRendererParams: {
routerLinkRendererComponentOptions: (param): IRouterLinkRendererComponentOptions => {
if (param.data.dispatch_adjustment) {
return {
routerLinkParams: ['/adjustments', param.data.dispatch_adjustment.id, 'edit'],
linkDescription: '#' + param.data.dispatch_adjustment.id
};
} else {
return {
textOnly: '-'
};
}
}
},
...
},

- 6,247
- 2
- 36
- 24

- 4,222
- 5
- 33
- 62
Instead of using href in cellRenderer , it's better to use cellrenderer framework as route link works in it. Another Disadvantage is if you use href then the entire angular application will reload again it changes the navigation state from imperative to popstate. The angular router works on the imperative state.
I had implemented something similar to Michael and Tom, with only [routerLink]
and no (click)
handler. But recently I started getting the dreaded warning:
Navigation triggered outside Angular zone, did you forget to call 'ngZone.run()'?
After experimenting for awhile I found this post and added the navigate click handler function, which made the application start working again, however I found that the 'Navigation triggered outside Angular zone' message was still appearing in the logs.
So while the (click)="navigate()"
call triggers the navigation inside the ngZone
,the [routerLink]
call is still being made, which bothered me. I really didn't want two attempts to navigate to happen - in case anything changed with a future API update.
I decided to replace the anchor tag with a span pseudoLink
.
.pseudoLink {
color: blue;
text-decoration: underline;
cursor: pointer;
}
@Component({
template: '<span class="pseudoLink" (click)="navigate()">{{mytitle}}</span>'
})
navigate() {
this.ngZone.run(
() => {
console.log("LinkRendererComponent: navigate: (", this.mylink, ")");
this.router.navigate([this.mylink]);
}
);
}
this.mylink
is defined in the agInit()
method based on parameters passed in via cellRendererParams
.
This works well for my main purpose which is to make the cell look like a link. Only thing I lost was the URL path popup in the browser status bar.
Hope this might help someone else.
Using a cell renderer is the correct solution but missing from the top answer is stopping the click event from reaching AgGrid:
cellRenderer: ({value}) => {
const a = document.createElement('a');
a.innerText = a.href = value;
a.target = '_blank';
// Prevent click from reaching AgGrid
a.addEventListener('click', event => { event.stopPropagation() });
return a;
}
If the click bubbles up to AgGrid it will cause row selection changes, etc if those are enabled.

- 6,247
- 2
- 36
- 24

- 11
- 1
I created a generic component that is usable for any link cell, uses no workarounds, and logs no warnings.
Usage
columnDefs = [
{
colId: 'My Column',
cellRendererFramework: AgGridLinkCellComponent,
cellRendererParams: {
// `text` and `link` both accept either an string expression (same as `field`) or a function that gets ICellRendererParams
text: 'title',
link: (params: ICellRendererParams) => `/my-path/${_.get(params, 'data.id')}`
}
}
]
Register the component in your AppModule
:
imports: [
AgGridModule.withComponents([
AgGridLinkCellComponent
])
]
The component itself:
import * as _ from 'lodash';
import {Component} from '@angular/core';
import {AgRendererComponent} from 'ag-grid-angular';
import {ICellRendererParams} from 'ag-grid-community';
@Component({
selector: 'app-ag-grid-link-cell-component',
template: '<a [routerLink]="link">{{ text }}</a>',
})
export class AgGridLinkCellComponent implements AgRendererComponent {
link: string;
text: string;
constructor() {
}
agInit(params: ICellRendererParams): void {
this.refresh(params);
}
refresh(params: ICellRendererParams): boolean {
const dataParams = params.colDef.cellRendererParams;
this.link = _.isFunction(dataParams.link) ? dataParams.link(params) : _.get(params.data, dataParams.link);
this.text = _.isFunction(dataParams.text) ? dataParams.link(params) : _.get(params.data, dataParams.text);
return false;
}
}

- 6,247
- 2
- 36
- 24
We had this problem, and its not straightforward.
We ended up solving it in a different way as we use AdapTable on top of ag-Grid.
So we created an AdapTable Action Column and in the RenderFunction provided the link. That worked best for us as we didnt always want the Link to appear so we could use the ShouldRender function to decide whether or not we wanted to display link for each row.

- 112
- 2
- 9