在 Angular 中处理手风琴的打开/折叠事件

IT技术 javascript twitter-bootstrap angularjs angular-ui
2021-03-17 04:59:06

如果我有这个代码:

<accordion-group heading="{{group.title}}" ng-repeat="group in groups">
      {{group.content}}
</accordion-group>

使用 AngularJS、angular-ui 和 Twitter Bootstrap,是否可以让手风琴在打开时调用一些动作?我知道我不能简单地添加ng-click,因为它在“编译”为 HTML 以打开/折叠组后已经使用。

6个回答

手风琴组还允许手风琴标题指令而不是将其作为属性提供。您可以使用它,然后通过 ng-click 将您的标题包装在另一个标签中。

<accordion-group ng-repeat="group in groups" heading="{{group.title}}" is-open="group.open">
  <accordion-heading>
    <span ng-click="opened(group, $index)">{{group.content}}</span>
  </accordion-heading>
</accordion-group>

示例:http : //plnkr.co/edit/B3LC1X?p=preview

这是我能找到的最干净的解决方案。谢谢,给我一杯啤酒!
2021-05-04 04:59:06
很酷的方式!+1 通过使用警报或一些 console.log 测试点击,小心不要在第一次尝试中放弃。它不起作用,请尝试使用控制器上您的作用域中存在的功能:) 我理解它不起作用的原因是因为 ng-click 不支持警报和控制台。
2021-05-12 04:59:06
是的,手风琴标题允许我们在点击时打开或关闭面板,但这不是展示如何从其他触发器打开面板的示例。
2021-05-13 04:59:06
这很好,唯一的问题是手风琴标题占据了整行,并且只有当您直接单击文本时才会调用打开的函数
2021-05-15 04:59:06
谢谢@AnmolSaaf:我试图用警报来测试它,我变得很生气!
2021-05-17 04:59:06

这是基于pkozlowski.opensource解决方案的解决方案。您可以使用动态定义的 Property
而不是在集合的每个项目上添加$watch在这里,你可以将绑定IsOpened的财产是开放的属性。

<accordion-group ng-repeat="group in groups" heading="{{group.title}}" is-open="group.IsOpened">
   {{group.content}}
</accordion-group>

因此,您可以在控制器中的每个集合项上动态添加IsOpened属性:

$scope.groups.forEach(function(item) {
  var isOpened = false;
  Object.defineProperty(item, "IsOpened", {
    get: function() {
      return isOpened;
    },
    set: function(newValue) {
      isOpened = newValue;
      if (isOpened) {
        console.log(item); // do something...
      }
    }
  });
});

使用属性而不是手表对性能更好。

这其实是目前最好的答案。
2021-04-20 04:59:06
我知道,所以基本上不鼓励OMG 谢谢-谢谢-谢谢之类的东西。所以让我说,如果我遇到你,我会给你买啤酒;) 这是一个很好的解决方案,没有手表的开销。
2021-05-07 04:59:06

is-open手风琴组上有一个指向可绑定表达式属性。当给定的手风琴组打开时,您可以观察这个表达式并执行一些逻辑。使用此技术,您可以将标记更改为:

<accordion-group ng-repeat="group in groups" heading="{{group.title}}" is-open="group.open">
   {{group.content}}
</accordion-group>

以便您可以在控制器中准备所需的监视表达式:

$scope.$watch('groups[0].open', function(isOpen){
    if (isOpen) {
      console.log('First group was opened'); 
    }    
  });

虽然上述工作在实践中使用可能有点麻烦所以如果你觉得这可以改进在https://github.com/angular-ui/bootstrap 中打开一个问题

@Michal 恐怕当前的实现并非微不足道。您可以像在此plunk中一样设置深度监视:plnkr.co/edit/bLnkvf?p=preview但我真的不能推荐这个...
2021-04-18 04:59:06
我不敢相信这不容易做到。完全是垃圾。当然,开发人员会希望在开放组以及何时更改时观看手风琴。这是微不足道的。
2021-05-04 04:59:06
我可以让观看更通用吗?就像 - 所以我不必'groups[0].open'为每一行都我事先不知道我会有多少行...
2021-05-11 04:59:06
@pkozlowski.opensource 我们可以is-open选择使用accordion-heading标记吗?
2021-05-14 04:59:06
@pkozlowski.opensource - 感谢举个例子。这当然是可行的,但你们打算正式向 Accordion 控件添加打开/关闭事件吗?原始 Bootstrap 可折叠控件有一个。
2021-05-15 04:59:06

这是一个受 kjv 回答启发的解决方案,它可以轻松跟踪打开的手风琴元素。我发现很难ng-click处理手风琴标题,尽管在<span>标签中围绕元素并添加 ng-click 效果很好。

我遇到的另一个问题是,虽然accordion元素是以编程方式添加到页面的,但内容却没有。当我尝试使用{{path}}链接到$scope变量的Angular 指令(即加载内容时,我会被击中undefined,因此使用了波纹管方法,该方法使用div嵌入的 ID 填充手风琴内容

控制器:

    //initialise the open state to false
    $scope.routeDescriptors[index].openState == false

    function opened(index) 
    {
        //we need to track what state the accordion is in
        if ($scope.routeDescriptors[index].openState == true){   //close an accordion
            $scope.routeDescriptors[index].openState == false
        } else {    //open an accordion
            //if the user clicks on another accordion element
            //then the open element will be closed, so this will handle it
            if (typeof $scope.previousAccordionIndex !== 'undefined') {
                $scope.routeDescriptors[$scope.previousAccordionIndex].openState = false;
            }
            $scope.previousAccordionIndex = index;
            $scope.routeDescriptors[index].openState = true;
    }

    function populateDiv(id)
    {
        for (var x = 0; x < $scope.routeDescriptors.length; x++)
        {
            $("#_x" + x).html($scope.routeDescriptors[x]);
        }
    }

HTML:

        <div ng-hide="hideDescriptions" class="ng-hide" id="accordionrouteinfo" ng-click="populateDiv()">
            <accordion>
                <accordion-group ng-repeat="path in routeDescriptors track by $index">
                    <accordion-heading>
                        <span ng-click="opened($index)">route {{$index}}</span>
                    </accordion-heading>
                    <!-- Notice these divs are given an ID which corresponds to it's index-->
                    <div id="_x{{$index}}"></div>
                </accordion-group>
            </accordion>
        </div>

我使用了一个关联数组来创建打开状态和模型对象之间的关系。

HTML是:

  <div ng-controller="CaseController as controller">


                <accordion close-others="controller.model.closeOthers">
                    <accordion-group ng-repeat="topic in controller.model.topics track by topic.id" is-open="controller.model.opened[topic.id]">
                       <accordion-heading>
                          <h4 class="panel-title clearfix" ng-click="controller.expand(topic)">
                         <span class="pull-left">{{topic.title}}</span>
                         <span class="pull-right">Updated: {{topic.updatedDate}}</span>
                          </h4>                           
                       </accordion-heading>
                  <div class="panel-body">

                      <div class="btn-group margin-top-10">
                          <button type="button" class="btn btn-default" ng-click="controller.createComment(topic)">Add Comment<i class="fa fa-plus"></i></button>
                      </div>
                     <div class="btn-group margin-top-10">
                         <button type="button" class="btn btn-default" ng-click="controller.editTopic(topic)">Edit Topic<i class="fa fa-pencil-square-o"></i></button>
                     </div>
                      <h4>Topic Description</h4>
                      <p><strong>{{topic.description}}</strong></p>
                      <ul class="list-group">
                          <li class="list-group-item" ng-repeat="comment in topic.comments track by comment.id">
                              <h5>Comment by: {{comment.author}}<span class="pull-right">Updated: <span class="commentDate">{{comment.updatedDate}}</span> | <span class="commentTime">{{comment.updatedTime}}</span></span></h5>
                              <p>{{comment.comment}}</p>
                             <div class="btn-group">
                               <button type="button" class="btn btn-default btn-xs" ng-click="controller.editComment(topic, comment)">Edit <i class="fa fa-pencil-square-o"></i></button>
                               <button type="button" class="btn btn-default btn-xs" ng-click="controller.deleteComment(comment)">Delete <i class="fa fa-trash-o"></i></button>
                             </div>
                          </li>
                      </ul>
                  </div>

                    </accordion-group>
                </accordion>

控制器代码段是:

   self.model = {
      closeOthers : false,
      opened   : new Array(),
      topics   : undefined
   };

“主题”填充在 AJAX 调用中。将“打开”状态与从服务器更新的模型对象分开意味着状态在刷新时得以保留。

我还声明了控制器 ng-controller="CaseController as controller"