Varun Sukheja
Varun Sukheja

Reputation: 6526

Angularjs - Same images loading multiple times

I am using ng-src in <img> tag, but whenever I am changing the ng-src on clicking the next or previous button, it loads the image in the browser (checked in network tab), although all the images are already loaded. So clicking on the next or previous button does not give a smooth experience and image firstly downloaded again by the browser and then rendered.

Can someone help me to solve this issue so that images which are already loaded by browser need not be loaded by making a new HTTP request.

<div class="slider" ng-style="{'width': ctrl.options.width,'height':ctrl.options.height}">
    <img class="materialboxed mainImage"
         ng-style="{'width': ctrl.options.width,'height':ctrl.options.height}"
         ng-src="{{ctrl.data[ctrl.currentImageIndex]}}">
    <i class="material-icons icon-arrow_left"
       ng-if="ctrl.displayLeftArrow"
       ng-click="ctrl.prevImg()">keyboard_arrow_left
    </i>
    <i class="material-icons icon-arrow_right"
       ng-if="ctrl.displayRightArrow"
       ng-click="ctrl.nextImg()">keyboard_arrow_right
    </i>
</div>

Here is the array of images that I am using:

[
        'https://static.pexels.com/photos/257360/pexels-photo-257360.jpeg',
        'https://lorempixel.com/580/250/nature/1',
        'https://lorempixel.com/580/250/nature/2',
        'https://lorempixel.com/580/250/nature/3',
        'https://lorempixel.com/580/250/nature/4',
    ]

Controller is here:

    preloader.preloadImages($scope.data);

    self.init = function () {
        self.currentImageIndex = 0;
        checkArrowVisibility();
    };

    self.prevImg = function () {
        self.currentImageIndex--;
        checkArrowVisibility();
    };
    self.nextImg = function () {
        self.currentImageIndex++;
        checkArrowVisibility();
    };

$scope.data holds the images array

Upvotes: 1

Views: 1428

Answers (2)

Vadim
Vadim

Reputation: 8789

As far as I can see, you preload all images upfront with preloader.preloadImages($scope.data);. In this case it is much easier not to put effort in to doing it programmatically, but just let the browser do it's job. To achieve this, I propose to put all images of slider into the DOM and just show/hide them on demand instead of setting different src (that is what actually triggers reload of the image again and again).

The essential part here would be <img ng-src="{{img}}" ng-repeat="img in ctrl.data" ng-show="$index === ctrl.cur" ...>. Pay attention that you should use ng-show and not ng-if here! Also you can utilize $index added by ng-repeat, which is quite handy in this case.

angular.module('app', []).controller('ctrl', function() {
  this.cur = 0;
  this.data = [
    'https://static.pexels.com/photos/257360/pexels-photo-257360.jpeg',
    'https://lorempixel.com/580/250/nature/1/',
    'https://lorempixel.com/580/250/nature/2/',
    'https://lorempixel.com/580/250/nature/3/',
    'https://lorempixel.com/580/250/nature/4/'
  ];
  this.width = 'auto';
  this.height = '250px'
})
<!DOCTYPE html>
<html ng-app="app">

  <head>
    <script data-require="[email protected]" data-semver="1.6.5" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.min.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body ng-controller="ctrl as ctrl">
    <h1>Slider</h1>
    <div>
      <img ng-src="{{img}}" ng-repeat="img in ctrl.data" ng-show="$index === ctrl.cur" alt="Image #{{$index}}" ng-style="{'width':ctrl.width, 'height': ctrl.height}"/>
      <br/>
      <button ng-click="ctrl.cur = ctrl.cur - 1" ng-show="ctrl.cur > 0">Previous</button>
      <button ng-click="ctrl.cur = ctrl.cur + 1" ng-show="ctrl.cur < ctrl.data.length - 1">Next</button>
    </div>
  </body>

</html>

Plunker: https://plnkr.co/edit/Mz9fo2MgcA36DYhQ8uRj?p=preview

You can see in the network tab of dev tools that images are loaded only once.

Upvotes: 0

zabusa
zabusa

Reputation: 2719

if you are using through $http service you can enable the cache by setting the cache parameter as true:

$http({
   method: 'GET',
   url: '/api/images',
   cache: true
});

otherwise use '$cacheFactory'to manually cache the data.

Upvotes: 1

Related Questions