ng-show需要双重评估'

时间:2014-10-05 22:59:09

标签: javascript angularjs ng-show

摘要

我想对ng-show使用需要首先评估的对象属性


实施例

我有一个包含lanOption(语言)对象的数组,我想在select元素中显示。是否显示语言取决于同样存在于范围内的变量couID(国家/地区)。

我希望通过附加属性在对象中包含关于显示或隐藏语言的逻辑,然后由ng-show使用,如下所示:

模型

$scope.lanOptions = [
   {name: "English", ngShow: "1"},                      
   {name: "Danish",  ngShow: "$scope.couID='DK'"},
   {name: "French",  ngShow: "$scope.couID='FR' || $scope.couID='BE'"},
   {name: "Dutch",   ngShow: "$scope.couID='NL' || $scope.couID='BE'"}
]

(应始终显示英文,仅在选择丹麦时显示丹麦语等)

视图

<select>
    <option ng-repeat="o in lanOptions" ng-show="{{o.ngShow}}" value="{{o.name}}">{{o.name}}</option>
</select>

问题

这里的重要部分是ng-show属性 - 有没有办法让它发挥作用?和/或有没有更好的方法让我失踪?我试过了filter:,但没有成功。

谢谢!


修改

澄清一下:这个例子实际上非常简化为我实际想做的事情。在我的实际问题中,还有许多变量值(可能)会影响每个选项的可见性。

举个例子,考虑

{name: 'Basque', ngShow: "($scope.couID=='ES' || $scope.couID=='FR') && $scope.inclMinority==true"}

{name: 'German', ngShow: "$scope.couID=='DE' || 
                          $scope.couID=='AU' ||
                          ($scope.couID=='BE' && $scope.inclMinority==true)"}

,或更复杂的表达。

这就是我不只是将couID数组作为属性添加到每个语言对象的原因 - 如果我之前没有明确提及,我很抱歉。

2 个答案:

答案 0 :(得分:1)

使用ngShow: "$scope.couID='DK'"}在模型@ $scope.中修复范围变量名称并不是一个好主意。如果您计划更改包含范围的变量名称,或者将此模型移植到某个位置,该怎么办?变得无法使用对属性名称$scope.couID进行条件检查的情况也是如此(可能您将其作为一种灵活性添加,以便您可以针对范围内的多个变量放置过滤条件,例如couID和各种不同的条件)。但是,即使您在ngShow中使用插值,绑定ngShow中的条件表达式也不会被评估,(可能您也可能会遇到语法错误)。

对于ng-show使用插值也不是一个好主意,因为它会查找即使是字符串"false"的truthy表达式(如果在布尔值上使用ng-show和插值,则会对其进行求值)价值,在你有条件的情况下离开,无论如何都不会默认工作),你最终会显示所有选项。

您应该退出ng-repeat用法来创建选择,而是开始使用 ng-options

通过保持模型中的条件,您可以使用 $parse 获取项目本身时评估ng-show表达式的一种方法,为什么要为ng-show添加不需要的监视?: -

在控制器中注入$parse,以便根据范围解析表达式: -

.controller('MainCtrl', function($scope, $parse) {
   //.....
   //In your method just return only necessary dropdown values
    $scope.getLanOptionsForCountry = function(){
      //Just filter it based on selected country and populate the select.
      return $scope.lanOptions.filter(function(itm){
                   return $parse(itm.ngShow)($scope); 
             });
    }
   //...

你的选择看起来就像: -

 <!-- Just added for the demo to select a country -->
 <select ng-model="couID" ng-options = "country.code as country.name for country in countries">
   <option value="">--Choose one--</option>
 </select>

<!-- This will be your selected, just added a placeholder option as well and an ngModel -->
 <select ng-model="language" ng-options = "lang.name for lang in getLanOptionsForCountry()">
   <option value="">--Choose one--</option>
 </select>

<强> Plnkr - Demo

或者您甚至可以通过删除其中的条件使您的视图模型更具可移植性,并为国家/地区代码设置过滤器,仅显示这些选项。

//Add a filter property which if present will display only for those country code else if will always display

 $scope.lanOptions = [
  {name: "English"},                      
  {name: "Danish",  filter: ["DK"]},
  {name: "French",  filter: ["FR", "BE"]},
  {name: "Dutch",   filter:["NL", "BE"]}
 ];

 $scope.getLanOptionsForCountry = function(){
    return $scope.lanOptions.filter(function(itm){
         return !itm.filter || (itm.filter.indexOf($scope.couID) + 1); 
    });
 }

<强> Plnkr2 - Demo

请参阅填充和对Array.Filter

的支持

答案 1 :(得分:0)

我会将您的语言选项更改为

$scope.lanOptions = [
{name: "English", countries: ["EN"]},                      
{name: "Danish",  countries: ["DK"]},
{name: "French",  countries: ["FR","BE"]},
{name: "Dutch",   countries: ["NL","BE"]}
]

并将ng-show更改为范围上的函数调用:

ng-show="showCountry(o)"

关于范围:

$scope.showCountry = function (lanOption) {
                  return (lanOption.countries.indexOf("EN")> -1 
                  ||lanOption.countries.indexOf($scope.couID)>-1)
}

编辑:实际上,进一步考虑了这一点,你可以放弃所有的ng-show,并通过调用一个简单返回的函数来替换你的ng-repeat 你需要的东西:

$scope.getLanOptionsForCountry = function () {
    return @scope.lanOptions.filter( function( item) {
                     return item.countries.indexOf("EN")>-1 || 
                     item.countries.indexOf($scope.couID)
                      });

}

然后

<select>
<option ng-repeat="o in getLanOptionsForCountry()" value="{{o.name}}">{{o.name}}</option>
</select>