使用AngularJS实现展开和折叠功能

24

我正在尝试使用AngularJS实现扩展和折叠的功能。但是,我没有找到一种优雅的方法来做到这一点,而不需要在控制器中操作DOM对象(这不是Angular的方式)。

目前,我有一种很好的方法可以用于单层的扩展和折叠。但是当我开始嵌套时,情况变得复杂,并且不能按照我想要的方式工作(在不应该扩展和折叠的多个区域之间进行扩展和折叠)。

问题出现在于我不知道如何使用ng-click发送唯一标识符,以仅扩展/折叠正确的内容。需要提及的是,这些项位于ng-repeat中,因此我不能自定义要发送的参数。

我能够使用这个jsfiddle帮助我使单层的扩展和折叠正常工作。然而,这是一种切换的方式来做到这一点,我希望用户能够同时保持其他已扩展的内容,而不仅仅是一个。因此,我所做的是使用一个数组,并且每次单击某个项时,将该单击项的索引添加到数组中并添加class:expanded。当用户再次单击时,该索引将从数组中删除,并且该区域将折叠。

我发现另一种方法是使用指令来实现。但是,我真的找不到任何示例来理解指令如何工作。当涉及编写指令时,我甚至不确定如何开始。

我的当前设置如下:

function Dexspander($scope) {
    $scope.ExpandArray = [];

    //Push or pop necessary elements for tracking
    $scope.DespopulatArray = function (identifier, element) {
    if (_.indexOf($scope.ExpandArray, identifier + element) != -1) {
            $scope.ExpandArray.splice(_.indexOf($scope.ExpandArray, identifier + element), 1);
        } else {
            $scope.ExpandArray.push(identifier + element);
        }
    }

    //Change class of necessary elements
    $scope.Dexspand = function (identifier, element) {
        if (_.indexOf($scope.ExpandArray, identifier + element) != -1) {
            return "expand";
        } else {
            return "collapse";
        }
    }
}

<div class="user-header" ng-repeat="user in users">
    <h1 ng-click="DespopulatArray('user', $index)">Expand</h1>
</div>
<div class="user-content" ng:class="Dexspand('user', $index)">
    <div class="content">
        <div class="user-information">
            <div class="info-header">
                <h1 ng-click="DespopulatArray('info', $index)>Some Information</h1>
            </div>
            <div class="info-contents" ng:class="Dexspand('info', $index)">
                stuff stuff stuff stuff...
            </div>
        </div>
    </div>
</div>

这种设置的问题在于,如果我有两个父级div都处于展开状态,并且它们下面都有要展开的内容,那么点击展开文本将会同时展开它们,因为它们不是独立的。


你可以在 Plunker 上放一个例子吗?那样我就能用指令帮你了。可以以这个为基础:http://plnkr.co/edit/gist:3662656 - Andrew Joslin
6个回答

27

您可以完全在HTML中解决这个问题:

<div>
  <input ng-model=collapse type=checkbox>Title
  <div ng-show=collapse>
     Only shown when checkbox is clicked
  </div>
</div>

这对ng-repeat也适用,因为它将为每个成员创建一个本地作用域。

<table>
  <tbody ng-repeat='m in members'>
    <tr>
       <td><input type=checkbox ng-model=collapse></td>
       <td>{{m.title}}</td>
    </tr>
    <tr ng-show=collapse>
      <td> </td>
      <td>{{ m.content }}</td>
    </tr>
  </tbody>
</table>

请注意,尽管repeat有自己的作用域,但最初它将从超级作用域中继承collapse的值。这使您可以在一个地方设置初始值,但可能会出乎意料。

当然,您可以重新设计复选框。参见http://jsfiddle.net/azD5m/5/

更新的fiddle:http://jsfiddle.net/azD5m/374/原始的fiddle使用关闭的</input>标签添加HTML文本标签,而不是使用<label>标签。


你为什么认为这些类型的指令到处都有?有点好奇。 - rolling stone
@Sridhar,你在谈论什么指令?我不明白这个问题。 - phil294

16
问题出在我不知道如何通过ng-click发送唯一标识符以仅展开/折叠正确的内容。 您可以在ng-click(ng-dblclick和ng-mouse事件)中传递$event,然后您可以确定哪个元素引起了该事件。
<a ng-click="doSomething($event)">do something</a>

控制器:

$scope.doSomething = function(ev) {
    var element = ev.srcElement ? ev.srcElement : ev.target;
    console.log(element, angular.element(element))
    ...
}

也请参阅http://angular-ui.github.com/bootstrap/#/accordion


可能对某些人有用。这里有一个教程。http://www.aneejian.com/angular-js-custom-directive-expand-collapse/ - Kannan Suresh

7
请参考http://angular-ui.github.io/bootstrap/#/collapse
function CollapseDemoCtrl($scope) {
  $scope.isCollapsed = false;
}



<div ng-controller="CollapseDemoCtrl">
    <button class="btn" ng-click="isCollapsed = !isCollapsed">Toggle collapse</button>
    <hr>
    <div collapse="isCollapsed">
        <div class="well well-large">Some content</div> 
    </div>
</div>

3

我刚使用 Angular 制作了一个简单的可折叠 zippy 组件,使用了 ng-show、ng-click 和 ng-init 指令。它仅实现了一层,但很容易扩展到多层。

将一个布尔变量分配给 ng-show 指令,并在标题点击时切换它。

这里查看。 enter image description here


2

这里提供一个使用ng-repeat的Angular JS简单易行的解决方案,希望能对你有所帮助。

var app = angular.module('myapp', []);

app.controller('MainCtrl', function($scope) {

  $scope.arr= [
    {name:"Head1",desc:"Head1Desc"},
    {name:"Head2",desc:"Head2Desc"},
    {name:"Head3",desc:"Head3Desc"},
    {name:"Head4",desc:"Head4Desc"}
    ];
    
    $scope.collapseIt = function(id){
      $scope.collapseId = ($scope.collapseId==id)?-1:id;
    }
});
/* Put your css in here */
li {
  list-style:none;
  padding:5px;
  color:red;
}
div{
  padding:10px;
  background:#ddd;
}
<!DOCTYPE html>
<html ng-app="myapp">
  <head>
    <meta charset="utf-8" />
    <title>AngularJS Simple Collapse</title>
    <script data-require="angular.js@1.5.x" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.11/angular.min.js" data-semver="1.5.11"></script>
</head>
<body ng-controller="MainCtrl">
<ul>
  <li ng-repeat='ret in arr track by $index'>
    <div ng-click="collapseIt($index)">{{ret.name}}</div>
    <div ng-if="collapseId==$index">
      {{ret.desc}}
    </div>
  </li>
</ul>
</body>
</html>

这应该能满足您的要求。这是一个有效的代码。
Plunkr链接: http://plnkr.co/edit/n5DZxluYHi8FI3OmzFq2?p=preview
Github链接: https://github.com/deepakkoirala/SimpleAngularCollapse

0

在HTML中

button ng-click="myMethod()">Videos</button>

在Angular中

 $scope.myMethod = function () {
         $(".collapse").collapse('hide');    //if you want to hide
         $(".collapse").collapse('toggle');  //if you want toggle
         $(".collapse").collapse('show');    //if you want to show
}

2
那不是“在angular中”。那是“在jquery中”。 - Robbie Smith

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接