ShadowFlame
ShadowFlame

Reputation: 3278

externalizing ng-class for table cells

I'm trying to see if angularJs is useful for me to create a team-management application.

The issue I have: I have a complex ng-class definition, being

ng-class="{'guard': ( guard.checked && day.func.indexOf('guard') != -1) }"

and it will prove to be bigger yet. I was wondering if there is a way to have basically this:

# pseudocode, needs to be translated to js/angularJs
function getClasses(){
    classes = ''
    if ('guard' in user.day.func and guardCheckBox == checked){
        classes = classes.append(' guard')
    }
    if ('f2' in user.day.func and f2CheckBox == checked){
        classes = classes.append(' f2')
    }
    ....
    if ('fx' in user.day.func and fxCheckBox == checked){
        classes = classes.append(' fx')
    }
    return(stripLeadingSpace(classes)
}

any tips on what to search, or any bits of code would be appreciated

a js-fiddle with what I have as of yet can be found here: http://jsfiddle.net/mTJDh/1/

code from the fiddle for dead links HTML: Guard

<!--
this snippet applies the class 'guard' to every cell when the checkbox 'Guard' is checked
-->
<div ng-controller="MyCtrl">
    <table ng-repeat="user in users">
        <tr>
            <td>{{user.name}}</td>
            <td ng-repeat="day in user.days" ng-class="{'guard': ( guard.checked && day.func.indexOf('guard') != -1) }">
                {{day.number}}
            </td>
        </tr>
    </table>
</div>

JS

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

function MyCtrl($scope) {
    $scope.users = [
        {name: 'PEDC',
        days : [{number:'1', func:'guard'},
                {number:'2', func:'guard'},
                {number:'3', func:'guard'},
                {number:'4', func:['guard','spoc']}
               ]
        },
        {name: 'JOVH',
        days : [{number:'1', func:'guard'},
                {number:'2', func:'guard'},
                {number:'3', func:'spoc'},
                {number:'4', func:'guard'}
               ]
        }
    ];
}

CSS

.pending-delete {
    background-color: pink
}
.guard {
    border:solid black 1px
}
.spoc {
    background-color: pink
}

EDIT:

This is the actual solution I use now:

http://jsfiddle.net/mTJDh/2/

basically: added functions isGuard, isSpoc and isHoliday to my controller, with the day as an argument these return true or false based on the json array.

idea gotten from here and https://docs.angularjs.org/api/ng/input/input%5Bcheckbox%5D

Upvotes: 1

Views: 568

Answers (3)

Raphael M&#252;ller
Raphael M&#252;ller

Reputation: 2200

I updated your fiddle:

http://jsfiddle.net/mTJDh/4/

use the ngClass as in the accepted answer:

<td ng-repeat="day in user.days" ng-class="getClasses(day)" day="day">
    {{day.number}}
</td>

but this time rewrite the method getClasses to return an array.

the array contains at the end every class you wants for a specific day.

$scope.getClasses = function(day){
    var classes = [];

    if($scope.spoc && $scope.isSpoc(day)) classes.push("spoc");
    if($scope.guard && $scope.isGuard(day)) classes.push("guard");
    if($scope.holiday && $scope.isHoliday(day)) classes.push("holiday");

    return classes;
}

and if you want a more generic one:

http://jsfiddle.net/mTJDh/5/

define:

var availableClasses = [
    "guard",
    "spoc",
    "holiday"]

and use a loop:

$scope.getClasses = function (day) {
    var classes = [];

    angular.forEach(availableClasses, function (value) {
       if ($scope[value] && day.func.indexOf(value) != -1) classes.push(value);
    });
    return classes;
}

Upvotes: 1

AlwaysALearner
AlwaysALearner

Reputation: 43947

ngClass also accepts methods defined on scope which return a boolean value. So you can do something like this:

<td ng-repeat="day in user.days" ng-class="{ 'guard' : getClass(day) }">
    {{day.number}}
</td>

JS

$scope.getClass = function(day){
    return $scope.guard.checked && day.func.indexOf('guard') != -1
}

Upvotes: 2

ivarni
ivarni

Reputation: 17878

I would use a directive, it was a bit hard to tell from your example which scope variables your CSS rules rely on (and what exactly the rules are), but hopefully it's enough to get started.

.directive('guardClass', [function() {

    return {
        restrict: 'A',
        scope: {
            guard: '=',
            user: '='
        },
        link: function(scope, element, attrs, controller) {
            scope.$watch(function() {
                //return enough info about scope.guard and scope.user
                //to know when one has changed
                return ...
            }, function() {
                var classes = [];
                if (...) {
                    classes.push('guard');
                }
                if (...) {
                    classes.push('f2');
                }
                ....
                if (...) {
                    classes.push('fx');
                }
                element.attr('class', classes.join(' '));
            });
        }
    };

}])

And then in HTML

<td guard-class guard="guard" user="user" />

You feed the directive the two (or more) objects it needs to calculate the CSS classes. The directive sets up a $watch to trigger whenever whatever properties on those objects change. It then finds all CSS classes that needs to be there and puts them on the element using angular element.

This saves you from cluttering up your controller with this logic, and it saves you from having extensive amounts of logic inside your templates.

Upvotes: 0

Related Questions