16

I have a list of items in an Angular UI Grid. When I click a row, I want to be taken to a different page. (In other words, each row in the grid will be a link.)

I imagine this must be a very common desire, although I haven't really seen any documentation on how to do it. What's a good way to accomplish this?

Jason Swett
  • 43,526
  • 67
  • 220
  • 351

4 Answers4

20

I figured out the answer myself. Here's my controller (ES6):

'use strict';

class TrackingRecordsCtrl {
  constructor($scope) {
    // The content of this template is included
    // separately 
    $scope.gridOptions = {
      rowTemplate: 'app/components/tracking-record/grid-row.html',
    };

    // This function is referenced from the row's template.
    // I'm just console.logging the row but you can of
    // course do anything you want with it.
    $scope.gridRowClick = row => {
      console.log(row);
      // or maybe $location.path(row.url)?
    };

    $scope.gridOptions.data = {
      // This of course can't just be an empty object.
      // Chances are you already have something defined
      // for gridOptions.data.
    };
  }
}

TrackingRecordsCtrl.$inject = ['$scope'];

export default TrackingRecordsCtrl;

And here's my row template (Jade):

.ui-grid-cell(
  ng-repeat='(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name'
  ng-class="{ 'ui-grid-row-header-cell': col.isRowHeader  }"
  ui-grid-cell=''
  ng-click='grid.appScope.gridRowClick(row)'
)

And as a bonus, here's my stylesheet (SCSS). I thought it would make sense to highlight the row under the cursor and use a pointer cursor to make it clearer that the rows are clickable.

.ui-grid-row {
  cursor: pointer;

  &:hover .ui-grid-cell {
    background-color: #CCC;
  }
}
Jason Swett
  • 43,526
  • 67
  • 220
  • 351
15

Here is the solution i used. https://stackoverflow.com/a/32815458/2452630

        yourCtrl.gridOptions = {
        enableFiltering: true,
        enableHiding : false,
        enableSorting: true,
        appScopeProvider : yourCtrl,
        rowTemplate: '<div ng-click="grid.appScope.doSomething(row)" ng-repeat="(colRenderIndex, col) in colContainer.renderedColumns track by col.uid" class="ui-grid-cell" ng-class="col.colIndex()" ui-grid-cell></div>',
    };

    yourCtrl.doSomething = function(row) {
        alert("lala");
    }
Community
  • 1
  • 1
KuN
  • 1,143
  • 18
  • 23
12

The question as I understand it: clicking a row in an Angular UI Grid should result in navigation to a related page (i.e. the row should behave like a link). For example, a list of contacts are displayed in the grid, and clicking on a row takes you to a contact details page.

Kudos to the OP for answering his own question in an innovative way. However, I prefer this answer as it does not require the creation of a custom row template. I have fleshed it out a bit more, as the OP did not seem satisfied with Kathir's example.

Firstly, understand that the following code sets up a listener function for whenever the row.isSelected property changes:

gridApi.selection.on.rowSelectionChanged($scope,function(row){
        //Do something when a row is selected
      });

I.e. whenever a row is clicked, this function will be called. Note the row parameter passed to the function which can be used to access the entity that the row represents. For example, if a row represented a contact entity, then you could access the contactId property of the row/entity that was selected. The following example uses UI Router's $state service to navigate to a contact details page passing the contactId obtained from the row.entity property:

this.gridOptions.onRegisterApi = function (gridApi) {
                //set gridApi to controller property
                this.gridApi = gridApi;
                gridApi.selection.on.rowSelectionChanged($scope, function (row) {
                    $state.go("contact.details.view", {contactId: row.entity.contactId});
                });
            }

Note that the $scope object is required to be passed in, even if you are using Controller as syntax. Refer to this article about Controller as syntax.

For a full example using Typescript (file references omitted for brevity):

"use strict"
export class ContactsCtrl {

    title: string;
    contacts: interfaces.IContact[] = [];
    gridAPI: any;
    gridOptions: any = {
        enableFullRowSelection: true,
        enableRowSelection: true,
        multiSelect: false,
        enableRowHeaderSelection: false,
        data: "vm.contacts",
        columnDefs: [
            { field: "contactId", displayName: "Contact ID", width: 100 },
            { field: "name", displayName: "Contact Name" }            ]
    }

    static $inject = ["$scope", "$state"];
    constructor(private $scope : ng.IScope, private $state : ng.ui.IStateService) {
        this.gridOptions.onRegisterApi = function (gridApi) {
            //set gridApi on scope
            this.gridApi = gridApi;
            gridApi.selection.on.rowSelectionChanged($scope, function (row) {
                $state.go("contact.details.view", {contactId: row.entity.contactId});
            });
        }
    }
}
angular.module("app.contacts").controller("ContactsCtrl", contacts.controllers.ContactsCtrl);
}
Community
  • 1
  • 1
Blake Mumford
  • 17,201
  • 12
  • 49
  • 67
  • Hi, I have just came across to your answer and I think you cannot call `$state` in that way, first thing the variable is private and so you need to use `this.$scope` and then because `this` is binded to `gridApi` doesn't it? – felix at housecat Jul 06 '16 at 19:37
4
  $scope.gridOptions.onRegisterApi = function( gridApi ) {
    $scope.gridApi = gridApi;
       gridApi.selection.on.rowSelectionChanged($scope,function(row){
        var msg = 'row selected ' + row.isSelected;
        //Open your link here.
      });
  };

http://plnkr.co/edit/EO920wsxuqr3YU8931GF?p=preview

Kathir
  • 6,136
  • 8
  • 36
  • 67
  • Hmm, I don't see how this answers the question. I can't click on any row in your Plunker, and if there's a way to adjust your custom template to result in a clickable row, it's not obvious to me. Am I misunderstanding something? – Jason Swett May 13 '15 at 20:13
  • Sorry, I re-read my question and realized it might be unclear. What I want is for each row of my grid to be a link that takes me to a different page. (I also updated my question to be clearer.) – Jason Swett May 13 '15 at 20:20
  • check the new plnkr and see – Kathir May 13 '15 at 20:24
  • 2
    That's closer but I'm not sure that it seems like an acceptable solution to me. A row selection doesn't seem relevant to a row simply being clicked. – Jason Swett May 13 '15 at 20:34
  • Presumably the selected row contains some information about what you want to happen. The api.selection.on.rowSelectionChanged event simply becomes where you perform whatever action you wish (in the questioner's case a view change) and get the row data to accomplish that. It's the UI-Grid eqivalent of onClick. – krimhorn Aug 10 '15 at 20:20