基于表达式结果的AngularJS格式

时间:2014-08-26 18:54:03

标签: javascript angularjs

我试图了解如何使用AngularJS完成条件格式化。

我的场景,我有一个表格,里面有很多这样的值:

<tr ng-repeat='r in row'>
  <td>{{r.valueA | number:0}}</td>
  <td>{{r.valueB | number:0}}</td>
  <td>{{r.valueA - r.valueB | number:0}}</td>
  <td>{{total.valueA - r.valueA | number:0}}</td>
  <td>{{total.valueA - (r.valueA - r.valueB | number:0)}}</td>
</tr>

我想要发生的是这些单元格在数字为负数时将文本更改为红色。

以下是我的尝试:

A)使用ng-class指令路线:

<tr ng-repeat='r in row'>
  <td ng-class="{'text-red':r.valueA < 0}">{{r.valueA | number:0}}</td>
  <td ng-class="{'text-red':r.valueB < 0}">{{r.valueB | number:0}}</td>
  <td ng-class="{'text-red':(r.valueA - r.valueB) < 0}">{{r.valueA - r.valueB | number:0}}</td>
  <td ng-class="{'text-red':(total.valueA - r.valueA) < 0}">{{total.valueA - r.valueA | number:0}}</td>
  <td ng-class="{'text-red':(total.valueA - (r.valueA - r.valueB)) < 0}">{{total.valueA - (r.valueA - r.valueB) | number:0}}</td>
</tr>

......它有效,但有很多不必要的打字。当然有更好的方法。

B)自定义过滤器但无法使其正常工作:

myApp.filter('numberVariance',
    ['$filter',
    function (filter) {
        var numberFilter = filter('number');
        return function (amount, fractionDigits) {
            if (value === "0") {
                return "-";
            }
            var value = numberFilter(amount, fractionDigits);
            if (amount < 0)
                return "<span class='text-red'>" + value + "</span>";
            return value;
        };
    }]);

...这会转义返回的HTML字符串。我宁愿找到一个不使用ng-html-bind或“不安全”字符串的解决方案。

C)自定义指令。这感觉它是最合适的,但我不能让它工作:

myApp.directive('varianceValue', function () {
    return {
        restrict: 'A',
        link: function (scope, el, attr) {
            $(el).toggleClass("text-red", ($(el).text().indexOf('-') > -1));
        },
    }
});

...这在首次加载时工作正常,但不会在值更新时切换类。

4 个答案:

答案 0 :(得分:1)

您可以使用angular ng-class指令,在计算值为负时添加适当的类。

这是最干净的方法(使用角度哲学)因为:

  • 它使用绑定到计算变量的CSS类

  • 此解决方案的每个部分都有不同的作用(css for the 视觉效果,控制班级的真/假值)

  • 它灵活,易于修改,可以轻松扩展(添加 更多的类,根据颜色获取颜色的不同逻辑 价值等)

  • 计算在控制器中执行

  • 至于额外输入:可以通过添加额外的(嵌套的)ng-repeat来为每行生成<td>来进一步减少。

一个工作示例:

HTML:

<style>
    .red {
        color: red
    }
</style>

<span ng-app="myApp" ng-controller="mainCtrl">
    <table>
        <tr ng-repeat='r in row'>
            <td ng-class="{ red: isRed(getColumnVal(r, 1)) }">
                {{getColumnVal(r, 1)}}
            </td>
            <td ng-class="{ red: isRed(getColumnVal(r, 2)) }">
                {{getColumnVal(r, 2)}}
            </td>
            <td ng-class="{ red: isRed(getColumnVal(r, 3)) }">
                {{getColumnVal(r, 3)}}
            </td>
        </tr>
    </table>
</span>

JS:

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

myApp.controller('mainCtrl', ['$scope', function ($scope) {

    // the array of objects*
    $scope.row = [
        {
            valueA: 1,
            valueB: 2
        },
        {
            valueA: 3,
            valueB: 4
        }
    ];

    // returns the value for the given object* and the given table column
    $scope.getColumnVal = function (o, col) {
        var columnVal = 0;

        switch (col) {
            case 1:
                columnVal = o.valueA
                break;
            case 2:
                columnVal = o.valueB;
                break;
            case 3:
                columnVal = o.valueA - o.valueB;
                break;
            default: 
                columnVal = 0;
        }

        return columnVal;
    };

    // returns true if the given val is smaller than zero, else returns false
    $scope.isRed = function (val) {
        var isRed = false;
        if (val < 0) {
            isRed = true;
        }
        return isRed;
    };

}]);

进一步减少打击:

通过添加额外的<td>

来避免写入每个ng-repeat

HTML:

<style>
    .red {
        color: red
    }
</style>
<span ng-app="myApp" ng-controller="mainCtrl">
    <table>
        <tr ng-repeat='r in row'>
            <td ng-repeat='c in columns' ng-class="{ red: isRed(getColumnVal(r, c)) }">
                {{getColumnVal(r, c)}}
            </td>
        </tr>
    </table>
</span>

并根据您的需要向控制器添加以下定义列的语句:

$scope.columns = [1, 2, 3]; // This is for 3 columns, extend to your needs

答案 1 :(得分:1)

使用$ timeout给出Angular时间来评估表达式,你的指令应该可以正常工作。

工作example

app.directive('varianceValue', function ($timeout) {
    return {
        restrict: 'A',
        link: function (scope, el, attr) {
          $timeout(function(){
            $(el).toggleClass("text-red", ($(el).text().indexOf('-') > -1));
          },0);
        },
    }
});

<强> HTML

<table>
  <tbody>
    <tr ng-repeat="r in row">
      <td variance-value>{{r.valueA | number:0}}</td>
      <td variance-value>{{r.valueB | number:0}}</td>
      <td variance-value>{{r.valueA - r.valueB | number:0}}</td>
      <td variance-value>{{total.valueA - r.valueA | number:0}}</td>
      <td variance-value>{{total.valueA - (r.valueA - r.valueB | number:0)}}</td>
    </tr>
  </tbody>
</table>

答案 2 :(得分:0)

我会使用ng-class,但是根据应用程序的设置方式,将逻辑拉出到控制器/服务中描述性命名的函数中。

答案 3 :(得分:0)

以下是我最终选择的解决方案。谢谢大家的贡献。

myApp.directive('varianceValue', [ function () {
    return {
        restrict: 'A',
        link: function (scope, el, attr) {
            scope.$watch(
                function () { return el.text() },
                function () { $(el).toggleClass("text-red", ($(el).text().indexOf('-') > -1)); }
            );
        },
    }
}]);

我弄乱了各种$ watch值,其中大多数都让应用程序爬行,但上面的版本保持强大。