简体   繁体   English

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

[英]AngularJS: Hide parent based on number of hidden children

I have the following code: 我有以下代码:

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

Imagine that I have 10 items. 想象一下我有10件物品。 When I click the button, I set the item.hide to true and the item disappear. 单击按钮时,将item.hide设置为true,该项目消失。 When I hide all 10 items, I want to hide the main div. 当我隐藏所有10个项目时,我想隐藏主div。 What's the best way to achieve this with AngularJS? 用AngularJS实现此目标的最佳方法是什么?

An approach might be to use a function like this: 一种方法可能是使用如下函数:

$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;
};

and change the ngHide attribute on the outer div: 并更改外部div上的ngHide属性:

ng-hide="checkItems()"

jsfiddle : http://jsfiddle.net/u6vkf6bt/ jsfiddlehttp : //jsfiddle.net/u6vkf6bt/

Another approach is to declare a $scope.allHidden variable and watch over the array like this: 另一种方法是声明$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);

This is checking when anything inside the array is changed, and check if all the hide attributes are set to true. 这是检查何时更改数组内部的任何内容,并检查是否所有hide属性都设置为true。

Then set it on the ngHide attribute: 然后在ngHide属性上进行设置:

ng-hide="allHidden"

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

Among the two, I would choose the first approach, because deep watching may cause performance issues: 在这两种方法中,我会选择第一种方法,因为深度监视可能会导致性能问题:

This therefore means that watching complex objects will have adverse memory and performance implications. 因此,这意味着观看复杂的对象将对内存和性能产生不利影响。

From here , under $watch(watchExpression, listener, [objectEquality]); 这里 $watch(watchExpression, listener, [objectEquality]); when objectEquality is set to true. objectEquality设置为true时。

Yet another approach would be updating the counter of hidden items whenever a single item is hidden. 另一种方法是每当隐藏单个项目时更新隐藏项目的计数器。 Of course this would require the hiding code to be placed within your controller, like this: 当然,这需要将隐藏代码放置在您的控制器中,如下所示:

$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;
    }
}

and the hiding would need to be done like this: 并且隐藏将需要像这样完成:

<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/ jsfiddlehttps : //jsfiddle.net/723kmyou/1/

Pros for this approach 这种方法的优点

  • no need to iterate over the full items array when doing the "should main div be hidden?" 进行“是否应隐藏main div?”时,无需遍历整个items数组? check -> possibly better performance 检查->性能可能更好

Cons for this approach 这种方法的缺点

  • you need to place the hideItem function inside your controller 您需要将hideItem函数放置在控制器中

A couple of reasons why I didn't like the other solutions: 我不喜欢其他解决方案的几个原因:

  • Time complexity is always O(n). 时间复杂度始终为O(n)。 instead of counting how many items are visible/hidden - a number we do not care about at all in this problem - we should just ask if there's at least one visible. 而不是计算可见/隐藏的项目数量-在这个问题中我们根本不在乎的数量-我们应该问是否至少有一个可见的项目。 better performance. 更好的性能。
  • Not reusable enough. 没有足够的可重用性。

My preferred solution is to actually look for the first visible item: http://plnkr.co/edit/FJv0aRyLrngXJWNw7nJC?p=preview 我的首选解决方案是实际查找第一个可见项目: 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>

You can even expand this by passing a selector to 'my-parent' attribute to be used in the directive. 您甚至可以通过将选择器传递给指令中要使用的'my-parent'属性来扩展它。 allows to better specify which items to look for. 可以更好地指定要查找的项目。

I like this approach as it has almost no assumptions. 我喜欢这种方法,因为它几乎没有任何假设。 This can be used for any scenario where children might be hidden. 这可用于可能隐藏孩子的任何情况。 not necessarily ng-repeat . 不一定是ng-repeat However the watch might be costly as we're using a :visible selector. 但是,由于我们使用:visible选择器,因此手表可能会很昂贵。

another - assuming ng-repeat is involved - is to watch the value on the scope - http://plnkr.co/edit/ZPVm787tWwx9nbJTNg1A?p=preview 另一个-假设涉及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>

The watch here might be less costly, not sure, but it doesn't handle the dom, so there's a good chance for that.. 这块手表的价格可能不太便宜(不确定),但它不能处理dom,因此有很大的机会。

While this is very similar to other solutions, it is implemented as a highly reusable directive, and looks for the first visible item. 尽管这与其他解决方案非常相似,但它是作为高度可重用的指令实现的,并寻找第一个可见项。

In my solutions I also assume jquery is available. 在我的解决方案中,我还假设可以使用jquery。 There are many other ways to implement this if required: AngularJS: element.show() in directive not working 如果需要,还有许多其他方法可以实现此目的: AngularJS:指令中的element.show()不起作用

regarding watch performance, not sure which way is better. 关于watch性能,不确定哪种方法更好。 I am using a function to evaluate the watched value and I am not sure if this is the best way to handle it. 我正在使用一个函数来评估监视的值,并且不确定这是否是处理它的最佳方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM