Ag-Grid单元格中的链接与链接的关联

31

我正在使用ag-grid构建angular 4应用程序,并且在尝试将链接放入单元格时遇到了问题。有人可以帮我解决这个问题吗? 谢谢


你找到这个问题的解决方案了吗?你愿意发布吗?看起来下面唯一的答案是针对JavaScript的,似乎你需要TypeScript的解决方案。 - Judy007
这个对我很有帮助:https://dev59.com/iqPia4cB1Zd3GeqP1JxW#yOUwoYgBc1ULPQZFMdLD - Ryan
9个回答

40
请查看此演示
cellRenderer: function(params) {
  return '<a href="https://www.google.com" target="_blank" rel="noopener">'+ params.value+'</a>'
}

在此演示中,“city”列的单元格值是超链接。


你的意思是单元格 Country 是一个超链接。 - onetwo12
Angular 4 使用 TypeScript,您上面提供的解决方案是针对 JavaScript 的。 - Judy007
我真的不明白为什么有些人毫无理由地给负评!我的回答是基于我使用ag-grid的经验,不知道为什么要被负评! - gunnerwhocodes
1
这是一个很好的答案,完全适用于Angular。如果在组件中注入Router,它会有一些函数,让你可以像在模板中使用routerLink属性一样构造路由链接的URL,或者有时候路由链接也足够容易直接构建,就像shr的答案一样。像下面所建议的构建可重用的RouterLinkRendererComponent这样的东西也可以工作,但不是必要的。 - reads0520

27

我前几天遇到了这个问题,它比我最初想象的要复杂一些。最终我创建了一个渲染器组件,向其中发送链接,并且需要一些 NgZone 魔法才能完全运行。你可以像这样在列定义中使用它:

cellRendererFramework: RouterLinkRendererComponent,
cellRendererParams: {
    inRouterLink: '/yourlinkhere',
}

组件中,inRouterLink 是您发送的链接,params.value 是单元格的值。这意味着您可以路由到您的 Angular 路由,它可能看起来像“yourlink/:id”。如果您不想要更通用的解决方案,也可以通过在模板中硬编码链接并且不使用 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]);
        });
    }
}

并在其中注册

@NgModule({
    imports: [
        AgGridModule.withComponents([
            RouterLinkRendererComponent,
        ])
    ],
})

更新:我已经写了一篇关于此事的博客文章:https://medium.com/ag-grid/enhance-your-angular-grid-reports-with-formatted-values-and-links-34fa57ca2952


1
谢谢你的答复。我在导航时遇到了问题,目标组件加载了一个空模板,没有调用 ngOnInit。我没有意识到 ag-grid 在 Angular 环境之外执行 CellRenderFrameworks。NgZone 来拯救。 - Slowbie
2
重要提示!不要忘记将组件RouterLinkRendererComponent添加到模块中作为entryComponent。entryComponents: [ RouterLinkRendererComponent ]。否则,您将收到大量的ag-grid渲染错误。 - hastrb
很棒的解决方案。我有一个改进版,对于那些认为需要更多灵活性的人,请看看我的版本 https://dev59.com/i1YO5IYBdhLWcg3wTPrk#62207311 - tom10271

10

这篇文章有点过时,但可能会对某些人有所帮助。在 Angular 5 中使用 TypeScript 的解决方案类似于 C.O.G 建议的方法。在组件的 TypeScript 文件中,列定义可以包含自定义的单元格渲染函数。

 columnDefs  = [
    {headerName: 'Client', field: 'clientName' },
    {headerName: 'Invoice Number', field: 'invoiceNumber',
        cellRenderer: (invNum) => 
              `<a href="/invoice/${invNum.value}" >${invNum.value}</a>` },
];
lambda函数是在呈现单元格时调用的。传递的参数“value”是可以用于生成自定义渲染的值。

2
使用href看起来没问题,但是这样做的问题是会重新加载整个Angular应用程序..(至少对我是这样?)routerLink似乎无效。 - Marius
@Marius,你是否为href中使用的链接设置了路由路径?如果路由设置正确,它不应该重新加载整个Angular应用程序。 - shr
hrefrouterLink是完全不同的故事...我会创建一个简单的组件,在模板中用routerLink包装它,然后将此组件作为列添加到columnDefs中。这几乎与Michael上面建议的相同。 - hastrb

3

受@Michael Karén启发

这是一个更灵活的改进版本。

  • 我们可以设置在链接中显示的文本
  • 我们可以传递多于2个routerLink参数
  • 根据数据解析routerLink
  • 支持目标
  • 仅当链接不可用时才显示文本
  • 如果您想要添加更多功能,只需进一步编辑此组件
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;
    }
}

这样,我们就可以通过列定义动态解析参数并仅在需要时返回文本。

{
...
    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: '-'
                };
            }
        }
    },
...
},

2

不要在cellRenderer中使用href,最好使用cellrenderer框架作为路由链接。另一个缺点是,如果使用href,则整个Angular应用程序将重新加载,从命令式导航状态更改为popstate。Angular路由器基于命令式状态工作。


2

我曾经实现了类似Michael和Tom的东西,只使用[routerLink]而没有(click)处理程序。 但是最近我开始收到令人恐惧的警告:

Navigation triggered outside Angular zone, did you forget to call 'ngZone.run()'?

经过一段时间的实验,我找到了这篇文章并添加了导航点击处理函数,这使得应用程序重新开始工作,但是我发现“Navigation triggered outside Angular zone”消息仍然出现在日志中。
因此,虽然(click)="navigate()"调用会在ngZone内触发导航,但[routerLink]调用仍然会被执行,这让我感到困扰。我真的不希望发生两次尝试导航——以防未来API更新时发生任何变化。
我决定用一个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 是在 agInit() 方法中根据通过 cellRendererParams 传递的参数定义的。

这对于使单元格看起来像链接的主要目的很有效。唯一失去的是浏览器状态栏中的URL路径弹出。

希望这可以帮助其他人。


1
使用单元格渲染器是正确的解决方案,但是顶部答案中缺少阻止点击事件到达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;
}

如果点击事件冒泡到 AgGrid,如果启用了行选择等功能,则会导致行选择更改。

谢谢,这个解决方案帮助我修复了问题。 - Ghost

1
我创建了一个通用组件,可用于任何链接单元格,不使用任何解决方法,并且不记录任何警告。
使用方法
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')}`
    }
  }
]

在你的AppModule中注册组件:
imports: [
    AgGridModule.withComponents([
      AgGridLinkCellComponent
    ])
]

组件本身:

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;
  }
}

0
我们曾经遇到过这个问题,而且它并不简单。 最终,我们通过在ag-Grid之上使用AdapTable以不同的方式解决了它。 因此,我们创建了一个AdapTable操作列,并在RenderFunction中提供了链接。对我们来说,这是最好的解决方案,因为我们并不总是希望链接出现,所以我们可以使用ShouldRender函数来决定是否要为每一行显示链接。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接