angular directive使用全局开关

时间:2015-08-07 12:08:21

标签: angularjs angularjs-ng-repeat angular-directive

所以,我脑海中有以下形象:

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

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

指令的作用:

  • 给定限制(在上例中:3)应将显示的条目限制为最多3个项目
  • 将鼠标悬停在(鼠标悬停)任何可见项目上时,列表的其余部分也会显示(展开)
  • 在mouseout上,其他项目将再次隐藏 - 仍有3个项目可见

因此,从用户的角度来看,重点是拥有一个可能很长的只读列表。为了不使我的布局混乱,我希望将列表限制为几个条目。只有当用户将鼠标悬停在压缩列表上时,它才会被展开。哎呀,这是一个很棒的功能!

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

  1. 指令compactList有一个priority > 1000,因此在ng-repeat之前执行。它通过添加CSS类来操作列表项模板,具体取决于$index以及添加mouseover和mouseout事件
  2. ng-repeat执行时,被操纵的列表模板将添加一个&#34;隐藏项&#34;使用$index < limitTo
  3. 的每个模板实例的CSS类
  4. 必须有全局切换(collapsed=false/true
  5. 在鼠标悬停时,指令全局开关collapsed被设置为假,例如通过例如ngClass将显示隐藏的项目。这意味着,列表是&#34;扩展&#34;
  6. 在mouseout上,指令全局开关collapsed再次设置为true。通过ngClass技巧,项目4 ... n将再次隐藏
  7. 我设法通过操纵模板完成任务。但是我没有为一个&#34;指令 - 全局开关&#34;提出一个合适的解决方案。我可以使用哪些Angular机制将这样的变量附加到compactList指令,只有一个实例对所有ng-repeat项有效?但是,它一定不是真的&#34;全局因为在同一页面上可能有多个compactList指令。因此,只有&#34;范围&#34;该指令。我在括号中写了范围,因为ngRepeat创建了多个范围所以我不确定&#34;父范围&#34;实际上是。

    由于ngRepeat<li>个项目进行了操作,而<ul>标记在compactList标记上,因此我认为将指令getChildFragmentManager().executePendingTransactions(); 置于同一级别因为ngRepeat可能是一个太深的层次。也许父元素必须配备这样的变量?但这听起来并不是很优雅。

    有人有想法如何解决这个问题吗?注意:我绝对不是在寻找一些hackish解决方案。我想知道如何以优雅,符合Angular的方式做到这一点。我希望人们看着我的代码去WOW而不是ARGH;)

1 个答案:

答案 0 :(得分:0)

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上。)

希望它有所帮助。

编辑:

(by 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);
      }
    }; 
  });