Garbage Mashers, Power + Group Custom
How to do a group-by in Angular using external AngularFilter library. Two custom directives for power button used in this example from a design/implementation problem I am having. Looking for the correct Design Pattern in AngularJS.
by Andrew Philips
October 14, 2014
HTML
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.24/angular.js"></script>
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.0.4/css/bootstrap-combined.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-filter/0.4.8/angular-filter.min.js"></script>
<table ng-controller="MasherCtrl" class="table-condensed">
<thead>
<tr class="hline-bot">
<th colspan=3>
<h3>Garbage Mashers, <small>Power + Group Custom</small></h3>
</th>
</tr>
<tr>
<th>Level</th>
<th>Masher</th>
<th>Power</th>
</tr>
</thead>
<tbody ng-repeat="(level, mashers) in allMashers | groupBy: 'level'">
<tr ng-if="mashers.length>1" class="hline-bot-grp">
<td>{{level}}</td>
<td></td>
<td class="power"><power-button masher-group="mashers"></power-button></td>
</tr>
<tr ng-repeat="masher in mashers" ng-class="{ 'hline-bot': $last}">
<td><span ng-if="$first==1&&mashers.length<2">{{masher.level}}</span></td>
<td>{{masher.name}}</td>
<td class="power"><power-button masher="masher"></power-button></td>
</tr>
</tbody>
</table>
CSS
th, .power {
text-align: center
}
tr th {
font-weight: bold
}
.indicate-off {
color: #B22222;
}
.indicate-unk {
color: #FFA500;
}
.indicate-on {
color: #228B22;
}
.bwy-button {
/* Use this to style new button with no border. */
border: none;
background: none;
padding: 5px 5px;
}
tr.hline-bot td, tr.hline-bot th {
border-bottom:1px double #999;
}
tr.hline-bot-grp td {
border-bottom:1px double #CCC;
}
td {
min-width: 125px;
}
JavaScript
(function () {
var rotatePower = function(v) { return {'-1':0,'0':1,'1':0}[v]; };
angular.module('myApp', ['angular.filter'])
.controller('MasherCtrl', ['$scope', '$parse', '$log', function ($scope, $parse, $log) {
$scope.allMashers = {
1: { id: 1, name: "3263827", power: 1, level: "Detention" },
2: { id: 2, name: "10 Fwd", power: 1, level: "Club" },
3: { id: 3, name: "00001", power: 0, level: "Overbridge" },
4: { id: 4, name: "8675309", power: 1, level: "Club" },
5: { id: 5, name: "THX1138", power: 0, level: "Detention" }
};
// This would dispatch an AJAX call performing Masher power
// change at server. Either that module subscribes to
// ui.power event or has an API that this module calls.
$scope.$on('ui.power', function(e,o) { $log.log(e.name + ": " + angular.toJson(o)); });
}])
.directive('powerButton', ['$parse', function ($parse) {
return { restrict: 'E',
require: '?^masherGroup',
scope: { m: "=?masher", g: "=?group" },
template: '<button class="bwy-button" ng-click="myOnClick()"><span ng-class="{\'indicate-on\':(m.power==1),\'indicate-unk\':(m.power==-1),\'indicate-off\':(m.power==0)}" class="glyphicon glyphicon-off"></span></button>',
link: function(scope, element, attr, masherGroupCtrl) {
if (masherGroupCtrl) {
scope.m = {};
masherGroupCtrl.watchGroup(function(nv, ov) { scope.m.power = nv; });
scope.myOnClick = function() { masherGroupCtrl.onClick(); };
}
else {
var setMasherPower = $parse("("+attr.masher+")"+".power").assign;
scope.myOnClick = function() {
setMasherPower(scope.$parent, rotatePower(scope.m.power));
scope.$emit('ui.power', { masher: scope.m});
}
}
}
};
}])
.directive('masherGroup', ['$parse', function($parse) {
...