ng-scrollbar is not working with ng-repeat

送分小仙女□ 提交于 2019-12-31 02:30:06

问题


In my app I want to use a custom scrollbar for a div. So I used ng-scrollbar, it is working fine with static data. But whenever I get the data using ng-repeat it is not working. Please help me in this regard. Thanks in advance.

myFile.html

<style>
  .scrollme {
    max-height: 300px;
   }
</style>

<div ng-app="myapp">
  <div class="container" ng-controller="myctrl">

    <button class="btn btn-info" ng-click="add();">add</button>
    <button class="btn btn-warning" ng-click="remove();">remove</button>

    <div class="well" >
      <div class="scrollme" ng-scrollbar bottom rebuild-on="rebuild:me">
        <h1>Scroll me down!</h1>
        <p ng-repeat="mi in me">{{mi.name}}</p>
      </div>
    </div>
  </div>
</div>

myCtrl.js

var myapp = angular.module('myapp', ["ngScrollbar"]);
myapp.controller('myctrl', function ($scope) {
    $scope.me = [];
    for(var i=1;i<=20;i++){
        $scope.me.push({"name":i});
    }
    var a = $scope.me.length;
    $scope.add = function(){        
    $scope.me.push({"name":$scope.me.length+1});
    $scope.$broadcast('rebuild:me');
    }
    $scope.remove = function(){
        $scope.me.pop();
    }
});

回答1:


Try adding the broadcast call to the end of your controller so it fires on controller load. If that doesn't work, try adding:

$timeout(function () {
    $scope.$broadcast('rebuild:me');
}, 0);
// 0 optional, without it the time is assumed 0 which means next digest loop.

at the end of your controller code, not inside the add function. If this works but the previous approach doesn't then that means ngRepeat didn't finish rendering it's dynamic content in time for the ngScrollbar to properly update.

UPDATE: in general, you might have to wrap the broadcast inside of the add() function in a timeout as well. The reason I say this is that I suspect what's going on is that you add data to the scope variable and then broadcast all in the same function call. What might be happening is that the broadcast event is caught and scrollbar recalculates before ngRepeat sees the updated scope data and adds its extra DOM elements. Btw, if you want to recalculate the scrollbar on add(), then you also want to do this on remove() as well.

So your add function would become:

$scope.add = function(){        
    $scope.me.push({"name":$scope.me.length+1});
    // wait until next digest loop to send event, this way ngRepeat has enough time to update(?)
    $timeout(function () {
        $scope.$broadcast('rebuild:me');
    });
}



回答2:


please try ng-scroll... another plugin, but without need of manual adjust. mentioned on:

AngularJS with ng-scroll and ng-repeat




回答3:


If you use jQuery, you can try jQuery Scrollbar - it has more options and fully CSS customizable.

Example with ng-repeat is here

JavaScript

var demoApp = angular.module('demoApp', ['jQueryScrollbar']);

demoApp.controller('SimpleController', function($scope){

    $scope.me = [];
    for(var i=1;i<=20;i++){
        $scope.me.push({"name":i});
    }

    $scope.add = function(){
        $scope.me.push({"name":$scope.me.length+1});
    }
    $scope.remove = function(){
        $scope.me.pop();
    }

    $scope.jqueryScrollbarOptions = {
        "onUpdate":function(container){
            setTimeout(function(){
                // scroll to bottom. timeout required as scrollbar restores
                // init scroll positions after calculations
                container.scrollTop(container.prop("scrollHeight"));
            }, 10);


        }
    };
});

HTML

<div data-ng-app="demoApp">
    <div data-ng-controller="SimpleController">
        <button class="btn btn-info" ng-click="add();">add</button>
        <button class="btn btn-warning" ng-click="remove();">remove</button>
        <div class="scrollbar-dynamic" data-jquery-scrollbar="jqueryScrollbarOptions">
            <h1>Scroll me down!</h1>
            <p ng-repeat="mi in me">{{mi.name}}</p>
        </div>
    </div>
</div>

CSS

.scrollbar-dynamic {
    border: 1px solid #FCC;
    max-height: 300px;
    overflow: auto;
}



回答4:


This might be a bit late.

The problem is even though you have added the content to scope variable, angular has not finished adding p tags to your DOM. If you try a simple console log like

console.log($('.well').find('p').length);

After pushing content to $scope.me, you will understand what is happening. (Need jQuery at least to debug)

The solution is far more complicated than you can imagine.

STEP 1:

Add a ng-controller to your ng-repeat (Yes. It is allowed)

<p ng-repeat="mi in me" ng-controller="loopController">{{mi.name}}</p>

STEP 2: Define loopController

demoApp.controller('loopController', function($scope) {
    $scope.$watch('$last', function(new_val) {
        new_val && $scope.$emit('loopLoaded', $scope.$index);
    });
});

This controller function is triggered whenever ng-repeat manipulates DOM. I'm watching $last which is a scope variable for ng-repeat. This will be set to true whenever, ng-repeat loads last element in DOM. When $last is set to true I emit one event loopLoaded. Since you are pushing values into $scope.me using a loop, this event will be triggered for every push.


STEP 3: Event handling

In your SimpleController (not simple anymore, eh?)

$scope.$on('loopLoaded', function(evt, index) {
    if (index == $scope.me.length-1) {
        $scope.$broadcast('rebuild:me');
    }
});

Once all the p elements are loaded, index sent to event will be equal to $scope.me.length-1. So you call scroll rebuild. That's it.

Here's a reference I used - AngularJS - Manipulating the DOM after ng-repeat is finished



来源:https://stackoverflow.com/questions/24663917/ng-scrollbar-is-not-working-with-ng-repeat

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