jgravois
jgravois

Reputation: 2579

Marking modified cell/row $dirty in ui-grid 3.0

I have a plunker that is ALMOST just like it is supposed to be. I have to add one requirement to it and I can't find it in the docs or on google.

The grid is set (to be like Excel) where you can begin to edit and the tab key will move from row to row. I need SOME WAY to mark a cell as $dirty if a change was made.

The requirement is an update button to save the ENTIRE grid if there were any changes (again, he wants it just like Excel).

Here's the plunker.

The issue: double-click an editable cell (name, status, M, T, W, H, F) and the tab key will cycle through the entire grid. If a cell value is changed, I need a way to mark it as dirty!

CODE: (index.html)

<!DOCTYPE html>
<html ng-app="app">

  <head>
    <script data-require="lodash.js@*" data-semver="3.10.0" src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.0/lodash.js"></script>
    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.js"></script>
    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular-touch.js"></script>
    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular-animate.js"></script>
    <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet" />
    <script src="http://ui-grid.info/docs/grunt-scripts/csv.js"></script>
    <script src="http://ui-grid.info/docs/grunt-scripts/pdfmake.js"></script>
    <script src="http://ui-grid.info/docs/grunt-scripts/vfs_fonts.js"></script>
    <script src="http://ui-grid.info/release/ui-grid.js"></script>
    <link rel="stylesheet" href="http://ui-grid.info/release/ui-grid.css" type="text/css" />
    <link rel="stylesheet" href="main.css" type="text/css" />
  </head>

  <body>
    <div ng-controller="MainCtrl">
      <strong>Data Length:</strong>
 {{ gridOptions.data.length | number }}
        <br />
      <strong>Last Cell Edited:</strong>
 {{msg.lastCellEdited}}
        <br />
      <div ui-grid="gridOpts" ui-grid-edit="" ui-grid-cellnav="" class="grid"></div>
    </div>
    <script src="app.js"></script>
  </body>

</html>

(app.js)

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

app.controller('MainCtrl', ['$scope', '$http', function($scope, $http) {
  $scope.$scope = $scope;
  $scope.pending_view = true;
  $scope.gridOpts = {
    enableCellEditOnFocus: true,
    enableGridMenu: true
  };

   var dataset = [{
    vote_pending: false,
    has_comment: false,
    is_stale: false,
    is_watched: false,
    disbursement_issue: false,
    name: "Jon",
    status: 1,
    M: 9,
    T: 9,
    W: 9,
    H: 9,
    F: 4
  }, {
    vote_pending: true,
    has_comment: true,
    is_stale: true,
    is_watched: true,
    disbursement_issue: true,
    name: "Robbie",
    status: 1,
    M: 8,
    T: 8,
    W: 8,
    H: 8,
    F: 8
  }, {
    vote_pending: false,
    has_comment: false,
    is_stale: true,
    is_watched: true,
    disbursement_issue: false,
    name: "Brad",
    status: 1,
    M: 8,
    T: 8,
    W: 8,
    H: 8,
    F: 8
  }, {
    vote_pending: false,
    has_comment: true,
    is_stale: false,
    is_watched: false,
    disbursement_issue: false,
    name: "Paul",
    status: 1,
    M: 8,
    T: 8,
    W: 8,
    H: 8,
    F: 8
  }, {
    vote_pending: false,
    has_comment: true,
    is_stale: false,
    is_watched: true,
    disbursement_issue: false,
    name: "Billie",
    status: 2,
    M: 8,
    T: 4,
    W: 4,
    H: 4,
    F: 0
  }];

  $scope.getTotal=function(a, b, c, d, e) {
    return a+b+c+d+e;
  };

  $scope.gridweek = true;

  var sByName = _.sortBy(dataset, 'name');
  var sPending = _.sortByAll(dataset, ['is_watched', 'vote_pending', 'has_comment', 'disbursement_issue', 'is_stale']).reverse();

  $scope.gridOpts.data = sPending;

  $scope.pendingSort = function() {
    if($scope.gridOpts.data === sByName) {
      $scope.gridOpts.data = sPending;
    } else if($scope.gridOpts.data === sPending) {
      $scope.gridOpts.data = sByName;
    }
  };

  $scope.gridOpts.columnDefs = [
    {
      name: 'id',
      enableCellEdit: false,
      enableColumnMenu: false,
      headerCellTemplate: 'pending.hdr.html',
      cellTemplate: 'pending.icons.html',
      width: '15%'
    }, 
    {
      name: 'name',
      enableCellEdit: true,
      displayName: 'Name',
      cellClass: 'text-left cBlue',
      headerCellClass: 'text-center bGreen',
      enableColumnMenu: false,
      width: '12%'
    }, 
    {
      name: 'status',
      enableCellEdit: true,
      displayName: 'Status',
      editableCellTemplate: 'ui-grid/dropdownEditor',
      enableColumnMenu: false,
      cellClass: 'text-left cBlue',
      cellFilter: 'mapStatus',
      headerCellClass: 'text-center bGreen',
      editDropdownValueLabel: 'status',
      editDropdownOptionsArray: [
        {
          id: 1,
          status: 'FT'
        }, 
        {
          id: 2,
          status: 'PT'
        }
      ],
      visible: $scope.gridweek,
      width: '14%'
    }, 
    {
      name: 'M',
      enableCellEdit: true,
      displayName: 'M',
      enableColumnMenu: false,
      type: 'number',
      cellFilter: 'number:1',
      cellClass: 'text-right cBlue',
      headerCellClass: 'text-center bGreen',
      width: '8%'
    }, 
    {
      name: 'T',
      enableCellEdit: true,
      displayName: 'T',
      enableColumnMenu: false,
      type: 'number',
      cellFilter: 'number:1',
      cellClass: 'text-right cBlue',
      headerCellClass: 'text-center bGreen',
      width: '8%'
    }, 
    {
      name: 'W',
      enableCellEdit: true,
      displayName: 'W',
      enableColumnMenu: false,
      type: 'number',
      cellFilter: 'number:1',
      cellClass: 'text-right cBlue',
      headerCellClass: 'text-center bGreen',
      width: '8%'
    },
    {
      name: 'H',
      enableCellEdit: true,
      displayName: 'H',
      enableColumnMenu: false,
      type: 'number',
      cellFilter: 'number:1',
      cellClass: 'text-right cBlue',
      headerCellClass: 'text-center bGreen',
      width: '8%'
    },
    {
      name: 'F',
      enableCellEdit: true,
      displayName: 'F',
      enableColumnMenu: false,
      type: 'number',
      cellFilter: 'number:1',
      cellClass: 'text-right cBlue',
      headerCellClass: 'text-center bGreen',
      width: '8%'
    },
    {
      field: 'total',
      enableCellEdit: false,
      displayName: 'Total',
      enableColumnMenu: false,
      type: 'number',
      cellFilter: 'number:1',
      cellClass: 'text-right',
      headerCellClass: 'text-center bGreen',
      cellTemplate: 'total.tmpl.html',
      width: '10%'
    }
  ];

  $scope.msg = {};

  $scope.gridOpts.onRegisterApi = function(gridApi) {
    //set gridApi on scope
    $scope.gridApi = gridApi;
    gridApi.edit.on.afterCellEdit($scope, function(rowEntity, colDef, newValue, oldValue) {
      $scope.msg.lastCellEdited = 'edited row id:' + rowEntity.id + ' Column:' + colDef.name + ' newValue:' + newValue + ' oldValue:' + oldValue;
      $scope.$apply();
    });
  };
}])

.filter('mapStatus', function() {
  var statusHash = {
    1: 'Full Time',
    2: 'Part Time'
  };

  return function(input) {
    if (!input) {
      return '';
    } else {
      return statusHash[input];
    }
  };
});

Upvotes: 2

Views: 5641

Answers (3)

Maciek Trzos
Maciek Trzos

Reputation: 1

In addition to merlins answer. His css style didn't work for me. What I did is:

.ui-grid-row-dirty div {
    background-color: yellow !important;
}

which will set every cells (within the row) bg color to yellow.

Upvotes: 0

merlin
merlin

Reputation: 34

Try to adding a thin layer on top of the dataset to track record dirty status.

var records = [];
angular.forEach(dataset, function (rawdata) {
    var record = {};
    //Track changed attrs, 
    //keys are the changed properties and 
    //values are an array of values [origValue, newValue].
    record.changedAttrs = {};

    //record dirty status
    Object.defineProperty(record, 'isDirty', {
        get: function () {
            return Object.getOwnPropertyNames(record.changedAttrs).length > 0; 
        }
    }); 

    angular.forEach(rawdata, function (value, key) {
        Object.defineProperty(record, key, {
            get: function () {
                return rawdata[key];  
            },

            set: function (value) {
                var origValue = record.changedAttrs[key] ? 
                    record.changedAttrs[key][0] : rawdata[key];

                if(value !== origValue) {
                    record.changedAttrs[key] = [origValue, value];
                } else {
                    delete record.changedAttrs[key];  
                }
                rawdata[key] = value;
            }
        })      
    });
    records.push(record);  
}); 

Here is the plunker. Providing a custom row template and an extra line of css, the row bg color will change to yellow when the row is dirty.

rowTemplate: '<div ng-repeat="(colRenderIndex, col) in colContainer.renderedColumns track by col.uid" ' + 
'ui-grid-one-bind-id-grid="rowRenderIndex + \'-\' + col.uid + \'-cell\'" ' + 
'class="ui-grid-cell" ng-class="{ \'ui-grid-row-header-cell\': col.isRowHeader , \'row-dirty\': row.entity.isDirty}" ' + 
'role="{{col.isRowHeader ? \'rowheader\' : \'gridcell\'}}" ui-grid-cell></div>'

css

.ui-grid-cell.row-dirty {
    background-color: yellow !important;
}

Upvotes: 2

Joao Polo
Joao Polo

Reputation: 2163

I create a dirty flag on scope:

$scope.dirty = false;

and I update the function what monitors editions:

gridApi.edit.on.afterCellEdit($scope, function(rowEntity, colDef, newValue, oldValue) {
  $scope.$apply(function(scope) {
    scope.dirty = true;
  });
});

please see on plunkr: http://plnkr.co/edit/bSTXqp7wzLDL74rN3PII?p=preview

Upvotes: 4

Related Questions