1
votes

In angular ui-grid, I need to set the cellClass of specific cells based on their value. To determine what the cell class should be, I need to make a rather expensive http lookup, and therefore need to make my cellClass function return a promise. However it doesn't look like ui-grid waits for the promise to resolve, as the cellClass doesn't get applied. Is it not possible or am I doing it wrong. This function is to illustrate was I need to happen. Ofcourse this would be a $http call instead of a $timeout:

function cellClassDeferred() {
    var defer = $q.defer();
    $timeout(function() {
      defer.resolve('yellow');
    }, 3000);
    return defer.promise;
  }

I've created a plunker to show my intension: http://plnkr.co/edit/HqlT4lpQZ5BA2pWjxIL0?p=preview

3

3 Answers

0
votes

No need to use promises. This is how you can do it

var app = angular.module('plunker', ['ui.grid', 'ui.grid.edit', 'ui.grid.cellNav']);

app.controller('MainCtrl', function($scope, $q, $timeout) {
  $scope.cls = '';
  
  $scope.gridOptions = {
    columnDefs: [{
      name: 'value1',
      displayName: 'Value 1',
      cellClass: cellClassDirect
    }, {
      name: 'value2',
      displayName: 'Value 2',
      cellClass: ''
    }, ],
    data: [{
      value1: 10,
      value2: 20
    }]
  };

  function cellClassDirect() {
    return 'red';
  }

$scope.setCellClass = function(){
    $timeout(function() {
      $scope.gridOptions.columnDefs[1].cellClass = 'yellow';
      $scope.gridOptions = angular.copy($scope.gridOptions);
    }, 3000);
}

});
<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <link data-require="bootstrap@~3.3.5" data-semver="3.3.6" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.css" />
    <link data-require="ui-grid@*" data-semver="3.0.7" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/3.0.7/ui-grid.css" />
    <script data-require="[email protected]" src="https://code.angularjs.org/1.3.20/angular.js" data-semver="1.3.20"></script>
    <script data-require="ui-grid@*" data-semver="3.0.7" src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/3.0.7/ui-grid.js"></script>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl" ng-init="setCellClass()">
    <div ui-grid="gridOptions" ui-grid-edit ui-grid-cellnav class="grid"></div>
  </body>

</html>

See Plnkr

0
votes

If your intention is to return the value 'yellow' after 3 seconds, that is not the way promises work.

This is erroneous

function cellClassDeferred() {
    var defer = $q.defer();
    $timeout(function() {
      defer.resolve('yellow');
    }, 3000);
    return defer.promise;
  }

A promise is returned immediately. The promise resolves sometime in the future. The resolved value is extracted from the promise with the .then method.

Think of a promise as a container for a future value. You can instruct the $q service what to do with that future value with the .then method.

function setFutureCellColor() {
    var promise = $timeout(function(){return 'yellow'}, 3000);

    promise.then (function (color) {
        //operation delayed 3 seconds
        $scope.gridOptions.columnDefs[1].cellClass = color;
        //trigger update of grid
        $scope.gridOptions = angular.copy($scope.gridOptions);
    };

    //container with future value
    //container returned immediately
    return promise;
};

Update

The same advise goes for using httpPromises:

function setGridFromUrl() {

    var httpPromise = $http(url);

    httpPromise.then (function (results) {
        //waits for results from server
        $scope.gridOptions.columnDefs = results.data.columnDefs;
        //trigger update of grid
        $scope.gridOptions = angular.copy($scope.gridOptions);
    };

};   
0
votes

@BoKDamgaard If I'm not mistaken, you are trying to do real time cell validation after a $http call. This is what you need to do.

You will need to use editableCellTemplate and cellTemplate properties in your columnDefs.

  $scope.gridOptions = {
      enableSorting: true,
      columnDefs: [
         { field: 'company',
           enableCellEdit: true,
           editableCellTemplate: "<div><form name=\"inputForm\"><input type=\"INPUT_TYPE\" ng-blur=\"grid.appScope.cellValidate(grid, row, col, rowRenderIndex, colRenderIndex)\" ng-class=\"'colt' + col.uid\" ui-grid-editor ng-model=\"MODEL_COL_FIELD\"></form></div>",
           cellTemplate: "<div ng-class='{\"red\":row.entity.validCompany === false, \"green\":row.entity.validCompany === true }' class='ui-grid-cell-contents' >{{COL_FIELD }}</div>"
         }
      ]
 };

I have created a Example: PLUNKER

and this is what it's doing:

  1. Add a row, and Input a value in editable row.
  2. On focus loose (blur), makes an $http call.
  3. Validates the input value with returned data.
  4. Valid value will be in GREEN, invalid will be in RED.

Note: This only works on "mouse blur", but not on "enter" keypress because ui-grid overrides any events from "enter" keypress to stop cell edit, and won't ever reach up to the point where "$http" could be invoked. But there is certainly a workaround for that.