Refresh Bootstrap ScrollSpy after Angular model changes

时光怂恿深爱的人放手 提交于 2019-12-18 03:02:30

问题


I am attempting to use the bootstrap scollspy to highlight list items generated by an angular repeater.

The problem I'm running into is that I'm refreshing the scrollspy plugin from an angular controller, before angular has applied the model changes to the view.

What is the angular way to ensure the scrollspy('refresh') call happens after the DOM itself has been updated (not just the angular model)?

Template:

<div class="span2" id="addressList">
    <ul class="nav nav-tabs nav-stacked affix">
       <li ng-repeat="addr in addresses"><a href="#{{addr.id}}">{{addr.id}}</a></li>
    </ul>
</div>

Controller:

$scope.httpSuccessCallback = function (data) 
     $scope.addresses.push(data);
     $('[data-spy="scroll"]').scrollspy('refresh'); //calls $('#addressList .nav > li > a')
 }

回答1:


Without knowing anything about scroll spy, here's how you generally want to use a JQuery plugin in Angular:

app.directive('scrollSpy', function (){
   return {
     restrict: 'A',
     link: function(scope, elem, attr) {
         elem.scrollSpy({ /* set up options here */ });

         //watch whatever expression was passed to the
         //scroll-spy attribute, and refresh scroll spy when it changes.
         scope.$watch(attr.scrollSpy, function(value) {
              elem.scrollSpy('refresh');
         });
     }
   };
});

Then in HTML:

<div scroll-spy="foo">Do something with: {{foo}}</div>

The above example is VERY generic, but it will basically apply your plugin to an element, and call 'refresh' or whatever on it every time $scope.foo changes.

I hope that helps.




回答2:


How I solved this, using Blesh's answer

Template:

  <body ng-app="address" ng-controller="AddressCtrl" scroll-spy="addresses">
    <div class="container">
      <form ng-submit="lookupAddress()">
        <input type="text" ng-model="addressText" />
        <button id="addressQueryBtn">Submit</button>
      </form>

      <div id="addressList">
        <ul>
          <li ng-repeat="addr in addresses">{{addr}}</li>
       </ul>
      </div>

    </div>
  </body>

Angular JS:

angular.module('address', []).
directive('scrollSpy', function($timeout){
  return function(scope, elem, attr) {
    scope.$watch(attr.scrollSpy, function(value) {
      $timeout(function() { elem.scrollspy('refresh') }, 200);
    }, true);
  }
});

function AddressCtrl($scope, $http) {
  $scope.addresses = [];

  $scope.lookupAddress = function() {
    $scope.addresses.push($scope.addressText);
    $scope.addressText = '';
  };
}

The third argument to scope.watch(...) is needed when the watched scope var is an object or array. Unfortunately, this solution still results in the unrecognized expression problem randomguy mentions in the comments. I ultimately resolved this by using a timeout in the watch function.




回答3:


There are a few challenges using Scrollspy within Angular (probably why AngularUI still doesn't include Scrollspy as of August 2013).

  1. You must refresh the scrollspy any time you make any changes to the DOM contents.

    This can be done, as has been suggested here, by $watching the element and setting a timeout for the scrollspy('refresh') call.

  2. You need to override the default behaviour of the nav elements if you wish to be able to use the nav elements to navigate the scrollable area.

This can be accomplished by using preventDefault to to prevent navigation and attaching a scrollTo function.

I've thrown a working example up on Plunker: http://plnkr.co/edit/R0a4nJi3tBUBsluBJUo2?p=preview




回答4:


I have been looking for a solution to this problem for a while but I wasn't able to find one. I ended up implementing my own by creating a scroll spy service with a few directives.

The service will keep track of all the spied sections and their offset. The directives will create a scroll event, highlight nav items and tell the service where all the sections are located. Since this implementation doesn't watch a scope variable, the application needs to broadcast a message to update all sections' offsets.

You can find my example on Github.



来源:https://stackoverflow.com/questions/14284263/refresh-bootstrap-scrollspy-after-angular-model-changes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!