angular 指令使用全局开关操作 ngRepeat 项目

angular directive manipulating ngRepeat items with global switch

所以,我脑海中出现了以下画面:

新指令 compactList 适用于包含执行以下操作的 ngRepeat 指令的元素:

<li ng-repeat="for item in items" compact-list limit-to="3">{{item}}</li>

指令的作用:

因此,从用户的角度来看,重点是拥有一个可能很长的只读列表。为了不弄乱我的布局,我想将列表限制为几个条目。只有当用户将鼠标悬停在压缩列表上时,它才会展开。天哪,多么好的功能!

从技术角度来看,这是我的基本概念:

  1. 指令 compactList 有一个 priority > 1000,因此在 ng-repeat 之前执行。它通过根据 $index 添加 CSS classes 以及添加鼠标悬停和鼠标移开事件
  2. 来操纵列表项模板
  3. ng-repeat执行时,被操纵的列表模板会为每个带有$index < limitTo
  4. 的模板实例添加一个"hide item"CSSclass
  5. 必须有全局开关(collapsed=false/true)
  6. 鼠标悬停时,指令全局开关 collapsed 设置为 false,例如ngClass 将显示隐藏的项目。也就是说,列表是 "expanded"
  7. 在 mouseout 上,指令全局开关 collapsed 再次设置为 true。通过 ngClass 技巧,项目 4...n 将再次被隐藏

我设法通过操作模板来完成任务。但是我没能为 "directive-global switch" 想出一个像样的解决方案。我可以使用什么 Angular 机制将这样的变量附加到 compactList 指令,并且只有一个实例对所有 ng-repeat 项有效?但是,它不能是 "really" 全局的,因为同一页上可能有多个 compactList 指令。所以,只对指令的 "scope" 全局。我在括号中写了范围,因为 ngRepeat 创建了 多个范围 所以我不确定 "parent scope" 实际在哪里。

由于 ngRepeat<li> 项目进行操作,这些项​​目相乘而不是 <ul> 标签,在我看来,将指令 compactList 放在与 ngRepeat 相同的级别可能太深了一层。也许父元素必须配备这样的变量?但这听起来不太优雅。

有人知道如何解决这个问题吗?注意:我绝对不是在寻找一些骇人听闻的解决方案。我想知道如何以优雅的 Angular-conform 方式做到这一点。我希望看到我的代码的人会惊叹而不是惊叹 ;)

在这个 plunker 中得到了一个很好的解决方案:

这是一个包含两个“列表”项的示例。

<div ng-repeat="list in lists">
  <div ng-mouseleave="list.expand = false" ng-mouseover="list.expand = true" ng-repeat="item in list">
    <div ng-if="$first">
      List n° {{listIndex}}
    </div> 
    <div ng-show="$index < 3 || list.expand">
      {{item.value}}
    </div>
  </div>
 </div>

我使用 ng-mouseleaveng-mouseover 将动态 属性 list.exand 设置为 truefalse.

值部分的显示取决于您想要的限制(可以在范围内的 var 中定义)以及列表是否应该扩展。

ng-show="$index < 3 || list.expand"

如果您认为这可以满足您的需求,请告诉我。无论如何,您需要对其进行一些调整以适应您的指令的工作方式。

如果你想帮助我集成它,请分享你的指令代码(如果你在 plunker 中放一个例子就更好了),我会尽力而为。

希望对您有所帮助

编辑:

我花了一些时间来实现这个指令,就在这里。

查看此plunker

中的用途

我想出了两个应该像这样使用的指令:

<div ng-repeat="(listIndex,list) in lists">
   <div compact-list>
     <div ng-click="getClExpand()" ng-repeat="item in list">
      <div ng-if="$first">
        List n° {{listIndex}}
      </div> 
      <div limit-to="2">
        {{item.value}}
      </div>
    </div>
   </div>
 </div>

compact-list指令添加了ng-mouseenterng-mouseleave指令。

limit-to根据你给的号码加上ng-show

compact-list 指令

app.directive('compactList', function ($compile) {
   return {
      restrict: 'A',
      controller:function($scope){
        $scope.clExpand = false;
      },
      replace: false,
      link: function link(scope,element, attrs) {
        //don't forget to remove the directive before the compile to avoid infinite digests.
        element.removeAttr("compact-list");
        element.attr("ng-mouseenter","clExpand = true");
        element.attr("ng-mouseleave","clExpand = false");
        $compile(element)(scope);
      }
    }; 
  });

limit-to 指令:

app.directive('limitTo', function ($compile) {
    return {
      restrict: 'A',
      replace: false,
      //You can't use limit-to withouth compact-list
      require:"^^compactList",
      link: function link(scope,element, attrs) {
        element.attr("ng-show","$index < "+attrs.limitTo+" || clExpand");
        //don't forget to remove the directive before the compile to avoid infinite digests.
        element.removeAttr("limit-to");
        $compile(element)(scope);
      }
    };  
});

加号:您可以通过将 limit-to 指令放置在您想要的任何位置来选择要隐藏项目的哪一部分。 (如果你想隐藏物品的描述,把它放在描述div,如果你想隐藏整个物品,把它放在整个物品div。)

希望对您有所帮助。

编辑:

(作者:andimeier)

scope=true 属性 添加到compact-list 指令中,它仍然更好(请参阅下面我的评论)。因此,compact-list 将是:

compact-list 指令

app.directive('compactList', function ($compile) {
   return {
      restrict: 'A',
      scope: true,
      controller:function($scope){
        $scope.clExpand = false;
      },
      replace: false,
      link: function link(scope,element, attrs) {
        //don't forget to remove the directive before the compile to avoid infinite digests.
        element.removeAttr("compact-list");
        element.attr("ng-mouseenter","clExpand = true");
        element.attr("ng-mouseleave","clExpand = false");
        $compile(element)(scope);
      }
    }; 
  });