ng节目需要'双重评估'

ng-show needs to 'double evaluate'

本文关键字:评估 节目 ng      更新时间:2023-09-26

摘要

对于ng-show,我想使用一个需要首先求值的对象属性


示例

我有一个包含lanOption(语言)对象的数组,我想将其显示在select元素中。是否显示语言取决于作用域中的变量couID(country)。

我想通过一个额外的属性在对象中包含关于显示或隐藏语言的逻辑,然后由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数组作为属性添加到每个语言对象中——如果我之前没有明确提到这一点,我很抱歉。

$scope.修复模型@ngShow: "$scope.couID='DK'"}中的作用域变量名不是一个好主意。如果您计划更改包含作用域的变量名,或者将此模型移植到某个地方,它将变得不可用。属性名称$scope.couID的条件检查也是如此(也许您添加了它作为一种灵活性,这样您就可以针对couID等作用域和各种不同的条件放置要针对多个变量评估的筛选条件)。然而,即使在绑定ngShow中的ngShow条件表达式中使用插值,也不会得到求值结果(可能还会出现语法错误)。

对ng-show使用插值也不是一个好主意,因为它会寻找即使是字符串"false"也是真实的表达式(这就是它的计算结果,如果你在布尔值上使用ng-show进行插值,那么不管你的情况如何,你都有默认情况下不起作用的条件),你最终会始终显示所有选项。

您应该停止重复使用ng来创建select,而是开始使用ng选项

一种方法是,通过在模型中保留条件,您可以在使用$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-演示

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

//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-演示

请参阅polyfill和对Array.Filter的支持

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

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

将ng显示更改为作用域上的函数调用:

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>