简体   繁体   中英

Loader by updating ng-repeat with ng-if

First, here is my fiddle so you can understand my problem : https://jsfiddle.net/860Ltbva/5/

I would like to display a loading message when the loop ng-repeat is loading, and hide it when all the elements are loaded.

I used this fiddle to help : http://jsfiddle.net/jwcarroll/ZFp3a/

This code uses a directive to know when the last element is loaded :

app.directive("repeatEnd", function() {
  return {
    restrict: "A",
    link: function(scope, element, attrs) {
      if (scope.$last) {
        scope.$eval(attrs.repeatEnd);
      }
    }
  };
});

First problem:

This work only if I load every elements, but I use an ng-if to filter it, and this is where I have some problems. Because if the last element isn't loaded, the $scope.$last isn't true. So instead of hiding the loader everytime and removing once loaded, it's removed only in one case.

The HTML:

<div class="test" ng-repeat="light in lights" ng-if="showLights(light.status)" repeat-end="onEnd()">
<span>{{light.name}} - {{light.status}}</span></div>

And the controller:

app.controller("MyCtrl", function($scope, $timeout) {
  $scope.lights = [];
  $scope.loadingPatients = true;
  $scope.showStatus = 'on';

 for (var x = 0; x < 10000; x=x+2) {
    $scope.lights[x] = {'name': 'kitchen', 'status':'off'};
    $scope.lights[x+1] = {'name': 'living room', 'status':'on'};
  }

  $scope.showStatusFct = function(status){
    $scope.loadingPatients = true;
    $scope.showStatus = status;
  };
  $scope.showLights = function(lightStatus) {
    if ($scope.showStatus == 'on') {
      if (lightStatus == 'on')
        return true;
    } else {
      if (lightStatus == 'off')
        return true;
    }
  }

  $scope.onEnd = function() {
    $scope.loadingPatients = false;
  };

});

Second Problem

The variable $scope.loadingPatients is updated once the file is loaded, and not as soon as I click, which is weird because you can't see the loader

Any idea for those problems? Thanks

After a while, I finally found a solution. I'm not sure it's the best but the performance are better and the loader works.

For that, I used the $interval method of angular, and used filter and limitTo in the ng-repeat loop. I finally removed the ng-if.

Here is the new fiddle : https://jsfiddle.net/timguignard/7p3rayjr/11/

I just increase the limitTo every few seconds thanks to the interval, which makes the ng-repeat going faster, and also makes the loader work. And it start loading as soon as the page is loading, you don't see the ng-repeat freezing at the beginning.

My last advice is actually not to use a too long ng-repeat, and to use the limitTo to a maximum. In the example, the limitTo is equal to the length of the object, but if I put 100,000 objects, it will still make the application freeze for a moment when you change the filter. If I put a maximum to 1,000 or even 10,000, you won't see it freeze.

Here is the code:

HTML

<div ng-controller="MyCtrl">
  <button ng-click="upFilter('on')">Show lights ON</button>
  <button ng-click="upFilter('off')">Show lights OFF</button>

  <div ng-show="loadingWait">==LOADING==</div>
  <div ng-hide="loadingWait">==LOADED==</div>
  Limit lights: {{limitLights}} - Max all lights: {{maxLights}}

  <div class="test" ng-repeat="light in lights | filter : filter | limitTo:limitLights">
      <span>{{light.name}} - {{light.status}}</span>
   </div>
</div>

And the Javascript

(function() {
    angular.element(document).ready(function() {
    var app = angular.module('myApp', []);

    app.controller("MyCtrl", function($scope, $interval) {
      $scope.lights = [];
      $scope.loadingWait = true;

      //set the data
      for (var x = 0; x < 10000; x = x + 2) {
        $scope.lights[x] = {
          'name': 'kitchen',
          'status': 'off'
        };
        $scope.lights[x + 1] = {
          'name': 'living room',
          'status': 'on'
        };
      }
      $scope.maxLights = $scope.lights.length;

      $scope.upFilter = function(stat) {
        $scope.loadingWait = true;
        $scope.filter = {
          status: stat
        };
        loading();
      }
      loading();

      //login with interval
      var myInterval;

      function loading() {
        $scope.loadingWait = true;
        $scope.limitLights = 1;
        myInterval = $interval(function() {
          if ($scope.limitLights > $scope.lights.length) {
             $interval.cancel(myInterval);
             myInterval = undefined;
             $scope.loadingWait = false;
          }
          $scope.limitLights += 1000;
        }, 100)
      }
    });

   //to make the fiddle work
   angular.bootstrap(document, ['myApp']);
  });
}());

Hope it can help if anyone needs it. If you have a better solution, feel free to share below I'll check it!

I also found this fiddle, which seems to use a better option. I'll try to check it too : http://jsfiddle.net/nikospara/b8thjobp/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM