user1464139
user1464139

Reputation:

How can I assign a class to a report not on odd, even rows but on the change of a date column?

I have a very simple report in AngularJS:

<div class="gridHeader">
   <div>User</div>
   <div>Date</div>
   <div>Count</div>
</div>
<div class="gridBody"
   <div class="gridRow" ng-repeat="row in rps.reports">
      <div>{{row.user}}</div>
      <div>{{row.date}}</div>
      <div>{{row.count}}</div>
   </div>
</div>

The report works but it's difficult to notice when the date changes.

Is there some way that I could assign a class to the grid row so that one date grid row has one class and the next date the grid row has another class. I think this is already available for odd and even rows with Angular but here I need it to work on every date change.

Upvotes: 14

Views: 369

Answers (7)

The.Bear
The.Bear

Reputation: 5855

I've done a different solution (PLUNKER) where whole work is inside the controller. Maybe is a little bit more of code, but you will gain a lot of performance if you have thousand records because you will avoid dirty checking of ng-class.
Additionally if your report is static and it won't have any changes, you can disable the two data binding...

CONTROLLER

vm.reports = addReportCssClases();

function addReportCssClases() {
    var reportsData = [...]; 
    var classes = ['dateOdd', 'dateEven'];
    var index = 0; 

    reportsData[0].cssClass = classes[index];

    for (var i = 1; i < reportsData.length; i++) {
      var row = reportsData[i]; 
      index = (row.date !== reportsData[i-1].date) ? (1 - index) : index;
      row.cssClass = classes[index] ;
    }

    return reportsData;
}

HTML

<div ng-repeat="row in vm.reports track by $index" class="gridRow {{::row.cssClass}}">
    <div>{{::row.user}}</div>
    <div>{{::row.date}}</div>
    <div>{{::row.count}}</div>
</div>

Upvotes: 6

Gaurav Kumar Singh
Gaurav Kumar Singh

Reputation: 1570

I have created a very simple and working solution for this using angular-filter, only you need to add dynamic class on gridRow.

working jsfiddle

HTML

<div ng-repeat="row in rps.reports" 
    class="gridRow {{row.date | filterDate}}">

Styles

.even {
  background-color: green;
  color: #fff;
}
.odd {
  background-color: red;
  color: #000;
}

Angular-filter

myApp.filter('filterDate', function() {
  var lastDate,
    count = 0,
    calssName = 'even';
  return function(date) {
    var newDate = new Date(date).toDateString();
    !lastDate && (lastDate = newDate);
    if (newDate != lastDate) {
      if (calssName == 'even') {
        calssName = 'odd';
      } else {
        calssName = 'even';
      }
    }
    lastDate = newDate;
    return calssName;
  }
});

Upvotes: 1

cnorthfield
cnorthfield

Reputation: 3501

You can add the class with an expression using the ngClass directive in the view:

(function() {

  'use strict';

  angular.module('app', []);

})();

(function() {

  'use strict';

  angular.module('app').controller('MainController', MainController);

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

  function MainController($scope) {

    var date = new Date();

    $scope.rps = {
      reports: [{
          user: 'User A',
          date: date.setDate(date.getDate() + 1),
          count: 5
        },
        {
          user: 'User B',
          date: date.setDate(date.getDate() + 2),
          count: 10
        },
        {
          user: 'User C',
          date: date.setDate(date.getDate()),
          count: 8
        },
        {
          user: 'User D',
          date: date.setDate(date.getDate() + 2),
          count: 6
        },
        {
          user: 'User E',
          date: date.setDate(date.getDate()),
          count: 20
        },
        {
          user: 'User F',
          date: date.setDate(date.getDate() + 3),
          count: 6
        }
      ]
    };

  }

})();
.gridHeader,
.gridRow {
  display: table-row;
}

.gridHeader>div,
.gridRow>div {
  display: table-cell;
  padding: 5px 10px;
}

.className {
  background: #ff0000;
  color: #fff;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.3/angular.min.js"></script>

<div ng-app="app" ng-controller="MainController as MainCtrl">

  <div class="gridHeader">
    <div>User</div>
    <div>Date</div>
    <div>Count</div>
  </div>
  <div class="gridBody">
    <div class="gridRow" ng-repeat="row in ::rps.reports track by $index" ng-class="::{'className': $index === 0 || $index > 0 && rps.reports[$index - 1].date !== row.date}">
      <div>{{::row.user}}</div>
      <div>{{::row.date | date: 'dd-MM-yyyy'}}</div>
      <div>{{::row.count}}</div>
    </div>
  </div>

</div>

Or add a boolean in the controller that you can use to trigger the className using the ngClass directive:

(function() {

  'use strict';

  angular.module('app', []);

})();

(function() {

  'use strict';

  angular.module('app').controller('MainController', MainController);

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

  function MainController($scope) {

    var date = new Date();

    $scope.rps = {
      reports: [{
          user: 'User A',
          date: date.setDate(date.getDate() + 1),
          count: 5
        },
        {
          user: 'User B',
          date: date.setDate(date.getDate() + 2),
          count: 10
        },
        {
          user: 'User C',
          date: date.setDate(date.getDate()),
          count: 8
        },
        {
          user: 'User D',
          date: date.setDate(date.getDate() + 2),
          count: 6
        },
        {
          user: 'User E',
          date: date.setDate(date.getDate()),
          count: 20
        },
        {
          user: 'User F',
          date: date.setDate(date.getDate() + 3),
          count: 6
        }
      ]
    };

    // add the classes to the reports
    addClasses($scope.rps.reports);

  /*
   * @name addClasses
   * @type function
   * 
   * @description
   * Adds a class to a report if the date is different to the previous
   *
   * @param {array} reports The reports to add classes to
   * @return nothing.
   */
    function addClasses(reports) {

      // loop through the reports to check the dates
      for (var i = 0, len = reports.length; i < len; i++) {

        // if the previous report a different date then the current report will have a class
        reports[i].hasClass = (i === 0 || reports[i - 1].date !== reports[i].date);

      }

    }

  }

})();
.gridHeader,
.gridRow {
  display: table-row;
}

.gridHeader>div,
.gridRow>div {
  display: table-cell;
  padding: 5px 10px;
}

.className {
  background: #ff0000;
  color: #fff;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.3/angular.min.js"></script>

<div ng-app="app" ng-controller="MainController as MainCtrl">

  <div class="gridHeader">
    <div>User</div>
    <div>Date</div>
    <div>Count</div>
  </div>
  <div class="gridBody">
    <div class="gridRow" ng-repeat="row in ::rps.reports track by $index" ng-class="::{'className': row.hasClass}">
      <div>{{::row.user}}</div>
      <div>{{::row.date | date: 'dd-MM-yyyy'}}</div>
      <div>{{::row.count}}</div>
    </div>
  </div>

</div>

Upvotes: 1

Raj Nandan Sharma
Raj Nandan Sharma

Reputation: 3862

This can be done with a one line given all the dates are actually date with the same format and not date time

<div class="gridHeader">
   <div>User</div>
   <div>Date</div>
   <div>Count</div>
</div>
<div class="gridBody">
   <div  ng-repeat="row in rps.reports" class="gridRow"  ng-class="{'backblue':$index>0 && row.date!=rps.reports[$index-1].date}">
      <div>{{row.user}}</div>
      <div>{{row.date}}</div>
      <div>{{row.count}}</div>
   </div>
</div>

your gridRow class will have to contain the background-color

.gridRow{
  //other styles
  background-color:red;
}

and the class backblue will have to have only the background-color

.backblue{
   background-color:blue !important;
}

IMPORTANT This will only work if the date field is only date and does not have time. If in any case it does have time you will have to convert each datetime to date

Upvotes: 3

Dilip Belgumpi
Dilip Belgumpi

Reputation: 648

var app = angular.module('sample', []);

app.controller('SampleController', function($scope) 
{
 $scope.data = [
    {
      user: "A",
      date: "3/2/2017"
    },
    {
      user: "B",
      date: "3/4/2017"
      
    },
    {
      user: "C",
      date: "4/3/2017"
    },
      {
      user: "D",
      date: "4/3/2017"
    },
      {
      user: "E",
      date: "4/3/2017"
    },
      {
      user: "F",
      date: "4/2/2017"
    }  
  ];
  
});
.same{
background-color:#ddd;

}

.differ{
background-color:yellow;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html ng-app="sample">
<head>

</head>
<body>


<div ng-controller="SampleController">
<table id="myTable">
<thead>
<tr>
   <th>User</th>
   <th>Date</th>
 </tr>
</thead>
<tbody>
   <tr ng-repeat="row in data">
      <td>{{row.user}}</td>
      <td class="same" ng-if="data[$index+1].date==row.date || data[$index-1].date==row.date">{{row.date}}</td>
      <td class="differ" ng-if="data[$index+1].date!=row.date && data[$index-1].date!=row.date">{{row.date}}</td>
   </tr>
</tbody>
</table>
</div>
</body>
</html>

Upvotes: 1

Keerthi Kumar P
Keerthi Kumar P

Reputation: 1604

A modified version of @ssougnez answer by storing the current date also in addition to color:

if(!(currentDate && currentDate === data.date)){
  currentColor = currentColor == "color1" ? "color2" : "color1";
  currentDate = data.date;
}

Plunker: http://plnkr.co/edit/o3YVBB

This might have less impact on performance than his version.

Upvotes: 1

ssougnez
ssougnez

Reputation: 5886

You can use ng-class with a function defined in your controller. For example:

var currentColor = "color1";

$scope.getClass = function(index)
{
  if (index !== 0 && $scope.data[index].date !== $scope.data[index - 1].date)
  {
    currentColor = currentColor == "color1" ? "color2" : "color1";
  }

  return currentColor;
}

And in your template:

<div class="gridRow" ng-repeat="(i, d) in data" data-ng-class="getClass(i)">

See the plunker: http://plnkr.co/edit/PPPJRJJ1jHuJOgwf9lNK

Upvotes: 5

Related Questions