agon024
agon024

Reputation: 1007

AngularJS / ui-bootstrap accordion - scroll to top of active (open) accordion on click

When a panel is opened I need to have it scroll back to the ".panel-title" of the one that was just clicked. I know that I can create a directive to do this such as (got this from this site):

.directive( 'scrollTop', scrollTop );

  function scrollTop() {
      return {
          restrict: 'A',
          link: link
      };
  }

  function link( $scope, element ) {
      $scope.collapsing = false;
      $scope.$watch( function() {
          return $(element).find( '.panel-collapse' ).hasClass( 'collapsing' );
      }, function( status ) {
          if ( $scope.collapsing && !status ) {
              if ( $(element).hasClass( 'panel-open' ) ) {
                  $( 'html,body' ).animate({
                      scrollTop: $(element).offset().top - 20
                  }, 500 );
              }
          }
          $scope.collapsing = status;
      } );
  }

And in the HTML I was supposed to use:

<div uib-accordion-group is-open="status.openPanel" scroll-top></div>

But this does not seem to work. When you click the second panel it opens the first and second panel and it never even scrolls to the top when opening the third one.

I just need it to scroll back to the ".panel-title" of the panel that was clicked. I think it is pretty ridiculous that this seems to be so difficult to do when a lot of the time the panel content can get pretty long and I think most people would want to scroll to the top of the info when a panel is opened.

I have seen other posts on here but they don't seem to be dealing with AngularJS. I am using " ui-bootstrap-tpls-2.1.3 "

EDIT - Here is a Plunker to play with if you would like.

Any help is greatly appreciated.

Upvotes: 7

Views: 3389

Answers (1)

Ja9ad335h
Ja9ad335h

Reputation: 5075

this may be a quick and dirty method, but works flawless

angular.module('ui.bootstrap.demo', ['ngAnimate', 'ui.bootstrap'])
  .controller('AccordionDemoCtrl', function($scope) {
    $scope.oneAtATime = true;

    $scope.groups = [{
      title: 'Dynamic Group Header - 1',
      content: 'Dynamic Group Body - 1'
    }, {
      title: 'Dynamic Group Header - 2',
      content: 'Dynamic Group Body - 2 Dynamic Group Header - 2 Dynamic Group Header - 2 Dynamic Group Header - 2 Dynamic Group Header - 2 Dynamic Group Header - 2'
    }];

    $scope.items = ['Item 1', 'Item 2', 'Item 3'];

    $scope.addItem = function() {
      var newItemNo = $scope.items.length + 1;
      $scope.items.push('Item ' + newItemNo);
    };

    $scope.status = {
      isFirstOpen: true,
      isFirstDisabled: false
    };

    //scrolling  
    var accordion = $('.accordion'), timeOut;
    accordion.on('click', '.panel-heading', function(e) {
      if(e.target.nodeName != 'SPAN') return;
      var element = this;
      clearTimeout(timeOut);
      //since we dont know the exact offsetTop for dynamic content
      //using timeout 350 which let angular complete its render
      timeOut = setTimeout(function() {
        accordion.animate({
          scrollTop: element.offsetTop -2
        }, 300);
      }, 350);
    });
  });
.accordion {
  max-height: 220px;
  overflow: auto;
  padding: 2px; 8px 0 0;
}
*:focus { outline: none !important; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.6/angular.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.6/angular-animate.js"></script>
<script src="https://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.14.0.js"></script>
<link href="https://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
<div ng-app="ui.bootstrap.demo">
  <div ng-controller="AccordionDemoCtrl">
    <script type="text/ng-template" id="group-template.html">
      <div class="panel {{panelClass || 'panel-default'}}">
        <div class="panel-heading">
          <h4 class="panel-title" style="color:#fa39c3">
          <a href tabindex="0" class="accordion-toggle" ng-click="toggleOpen()" uib-accordion-transclude="heading"><span
            ng-class="{'text-muted': isDisabled}">{{heading}}</span></a>
        </h4>
        </div>
        <div class="panel-collapse collapse" uib-collapse="!isOpen">
          <div class="panel-body" style="text-align: right" ng-transclude></div>
        </div>
      </div>
    </script>

    <div class="accordion">
      <uib-accordion close-others="oneAtATime">
        <uib-accordion-group heading="Static Header, initially expanded" is-open="status.isFirstOpen" is-disabled="status.isFirstDisabled">
          This content is straight in the template.
        </uib-accordion-group>
        <uib-accordion-group heading="{{group.title}}" ng-repeat="group in groups">
          {{group.content}}
        </uib-accordion-group>
        <uib-accordion-group heading="Dynamic Body Content">
          <p>The body of the uib-accordion group grows to fit the contents</p>
          <button type="button" class="btn btn-default btn-sm" ng-click="addItem()">Add Item</button>
          <div ng-repeat="item in items">{{item}}</div>
        </uib-accordion-group>
        <uib-accordion-group heading="Custom template" template-url="group-template.html">
          Hello
        </uib-accordion-group>
        <uib-accordion-group heading="Delete account" panel-class="panel-danger">
          <p>Please, to delete your account, click the button below</p>
          <p>Please, to delete your account, click the button below</p>
          <p>Please, to delete your account, click the button below</p>
          <button class="btn btn-danger">Delete</button>
        </uib-accordion-group>
        <uib-accordion-group is-open="status.open">
          <uib-accordion-heading>
            I can have markup, too! <i class="pull-right glyphicon" ng-class="{'glyphicon-chevron-down': status.open, 'glyphicon-chevron-right': !status.open}"></i>
          </uib-accordion-heading>
          This is just some content to illustrate fancy headings.
        </uib-accordion-group>
      </uib-accordion>
    </div>
  </div>
</div>

Upvotes: 1

Related Questions