AngularJS:根据隐藏的子项数隐藏父项

时间:2015-04-09 12:44:43

标签: javascript angularjs

我有以下代码:

<div ng-hide="items.length == 0">
    <li ng-repeat="item in items" ng-hide="item.hide == true">
        {{ item.name }} <hide-button />
    </li>
</div>

想象一下,我有10件物品。当我单击按钮时,我将item.hide设置为true,项目消失。当我隐藏所有10个项目时,我想隐藏主要div。使用AngularJS实现这一目标的最佳方法是什么?

3 个答案:

答案 0 :(得分:5)

一种方法可能是使用这样的函数:

$scope.checkItems = function () {
    var total = $scope.items.length;
    for (var i = 0; i < $scope.items.length; ++i) {
        if ($scope.items[i].hide) total--;
    }
    return total === 0;
};

并更改外部div上的 ngHide 属性:

ng-hide="checkItems()"

jsfiddle http://jsfiddle.net/u6vkf6bt/

另一种方法是声明一个$scope.allHidden变量并监视数组:

$scope.$watch('items', function (newItems) {
    var all = true;
    for (var i = 0; i < newItems.length; ++i) {
        if (newItems[i].hide !== true) all = false;
    }
    $scope.allHidden = all;
}, true);

这是检查数组中的任何内容何时更改,并检查是否所有hide属性都设置为true。

然后在 ngHide 属性上设置它:

ng-hide="allHidden"

jsfiddle http://jsfiddle.net/u6vkf6bt/1/

在这两者中,我会选择第一种方法,因为深度观察可能会导致性能问题:

  

因此,这意味着观看复杂的物体会产生不利影响   记忆和表现的影响。

$watch(watchExpression, listener, [objectEquality]);设置为true时objectEquality下的here

答案 1 :(得分:1)

另一种方法是在隐藏单个项目时更新隐藏项目的计数器。当然,这需要将隐藏代码放在您的控制器中,如下所示:

$scope.allHidden = false;
// if items can have hide = true property set already from the start
var hiddenItems = $scope.items.filter(function (item) { 
    return item.hide; 
}).length;
// or if they are all initially visible, a straightforward approach:
// var hiddenItems = 0;
$scope.hideItem = function (item) {
    item.hide = true;
    hiddenItems++;
    if (hiddenItems === $scope.items.length) {
        $scope.allHidden = true;
    }
}

隐藏将需要这样做:

<li ng-repeat="item in items" ng-hide="item.hide == true">{{ item.name }}
    <button ng-click="hideItem(item)">hide</button>
</li>

jsfiddle https://jsfiddle.net/723kmyou/1/

这种方法的优点

  • 在执行&#34时不需要遍历完整的项目数组;是否应该隐藏主要的div?&#34;检查 - &gt;可能性能更好

这种方法的缺点

  • 您需要将hideItem函数放在控件中

答案 2 :(得分:1)

我不喜欢其他解决方案的几个原因:

  • 时间复杂度始终为O(n)。而不是计算可见/隐藏的项目数量 - 这个问题我们根本不关心的数字 - 我们应该问一下是否至少有一个可见。更好的性能。
  • 不够可重复使用。

我首选的解决方案是实际查找第一个可见项: http://plnkr.co/edit/FJv0aRyLrngXJWNw7nJC?p=preview

angular.module('MyApp',[]);

angular.module('MyApp').directive('myParent', function(){
    return {
      restrict: 'A',
      link:function(scope, element){
        scope.$watch(function(){
          return element.find('>:visible:first').length > 0;
        }, function( visible ){
            if ( visible ){
              element.show(); 
            }else{
              element.hide(); 
            }
        })
      }
    }
});

<div my-parent>
  <div class="hidden">one child</div>
  <div class="hidden">another child</div>
</div>
<div my-parent>
  <div class="hidden">third child</div>
  <div>another child</div>
</div>

您甚至可以通过将选择器传递给要在指令中使用的“my-parent”属性来扩展它。允许更好地指定要查找的项目。

我喜欢这种方法,因为它几乎没有任何假设。 这可以用于可能隐藏子项的任何场景。不一定是ng-repeat。 但是,当我们使用:visible选择器时,手表可能会很昂贵。

另一个 - 假设涉及ng-repeat - 是观察范围的价值 - http://plnkr.co/edit/ZPVm787tWwx9nbJTNg1A?p=preview

app.directive('myParent', function(){
    return{
      restrict: 'A',
      link: function(scope, element,attrs){
         scope.$watch(function(){
         try{
             value = scope.$eval(attrs.myParent);
             var i = value.length-1;
             for ( ; i >= 0; i-- ){
                if ( value[i].hide != false ){
                  return true;
             }
          }
       }catch(e){
           return false
       }
        return false;
     }, function( newValue ){       
            if ( !!newValue ) { element.show(); } else {  element.hide();}
        })
    }
 }});


<ul my-parent="awesomeThings">
  <li ng-repeat="thing in awesomeThings">{{thing.value}}</li>
</ul>

这里的手表可能成本较低,不太确定,但它不能处理dom,所以这很有可能......

虽然这与其他解决方案非常相似,但它是作为一个高度可重复使用的指令实现的,并且会查找第一个可见项。

在我的解决方案中,我也假设jquery可用。 如果需要,还有许多其他方法可以实现此目的: AngularJS: element.show() in directive not working

关于watch表现,不确定哪种方式更好。我正在使用一个函数来评估观察值,我不确定这是否是处理它的最佳方法。