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')
}
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With