Over a million developers have joined DZone.

How to Implement a Smart Chunking Bootstrap Carousel With AngularJS

Read on and learn how to create a "smart chunking carousel" (one that displays the optimal amount of images based on a user's screen size) by following Matt Raible's tutorial.

· Web Dev Zone

Start coding today to experience the powerful engine that drives data application’s development, brought to you in partnership with Qlik.

I've been helping a client develop a project management application for the last several months. One of the features I implemented uses UI Bootstrap's carousel directive to display a list of project templates to choose from when creating a new project. Rather than displaying one at a time, we wanted to display as many as the user's screen would allow. That is, if they were on a large monitor, we wanted to display five templates, a medium size monitor would display three and so on. This is a story of how I implemented a smart chunking carousel.

To begin, I made it possible to show groups of items in the carousel using array chunking.

function chunk(arr, size) {
  var newArr = [];
  var arrayLength = arr.length;
  for (var i = 0; i < arrayLength; i += size) {
    newArr.push(arr.slice(i, i + size));
  }
  return newArr;
}

Using UI Bootstrap's example code, I created $scope.chunkedSlides from $scope.slides.

$scope.chunkSize = 5;

// chunk slides so there's two per chunk by default
$scope.chunkedSlides = chunk($scope.slides, $scope.chunkSize);

Next, I changed the HTML template to read the grouped slides, and show each one.

<uib-carousel active="active" interval="0" no-wrap="true">
  <uib-slide ng-repeat="row in chunkedSlides">
    <div class="row">
      <div ng-repeat="slide in row track by $index" class="slide">
        <img ng-src="{{slide.image}}">
        <div class="carousel-caption">
          <h4>Slide {{slide.id}}</h4>
          <p>{{slide.text}}</p>
        </div>
      </div>
    </div>
  </uib-slide>
</uib-carousel>

This was enough to get five squares on a large monitor.

Image title

However, I wanted to go further and reduce the number per group on smaller monitors. I created aSmartChunking service that defined how many per group for each possible width.

angular.module('app').service('SmartChunking', function() {
  var large = 1600;
  var medium = 1200;
  var small = 1024;
  var xsmall = 800;

  this.getChunkSize = function(width) {
    var chunkSize;
    if (width >= large) {
      chunkSize = 5;
    } else if (width >= medium) {
      chunkSize = 4;
    } else if (width >= small) {
      chunkSize = 3;
    } else if (width >= xsmall) {
      chunkSize = 2;
    } else {
      chunkSize = 1;
    }
    return chunkSize;
  }
});

I wrote a smart-chunking directive to fire an event with the chunk size.

angular.module('app').directive('smartChunking', function($window, SmartChunking) {
  return {
    restrict: 'A',
    link: function($scope) {
      var w = angular.element($window);

      // window.outerWidth works on desktop, screen.height on iPad (width returns 768)
      var width = ($window.outerWidth > 0) ? $window.outerWidth : screen.height;
      var chunkSize = SmartChunking.getChunkSize(width);
      if (chunkSize !== 5) {
        $scope.$emit('change-chunk-size', chunkSize);
      }

      $scope.getWidth = function() {
        return ($window.outerWidth > 0) ? $window.outerWidth : screen.width;
      };

      $scope.$watch($scope.getWidth, function(newValue, oldValue) {
        if (newValue !== oldValue) {
          var chunkSize = SmartChunking.getChunkSize(newValue);
          $scope.$emit('change-chunk-size', chunkSize);
        }
      });

      w.bind('resize', function() {
        $scope.$apply();
      });
    }
  }
});

Then I added a listener for this in the controller that populated the carousel.

$scope.$on('change-chunk-size', function(event, data) {
  if (data !== $scope.chunkSize) {
    $scope.chunkedSlides = chunk($scope.slides, data);
    $scope.chunkSize = data;
  }
});

The final step was adding the smark-chunking directive to each slide and dynamically determining its col-sm-*class.

<div ng-repeat="slide in row track by $index" class="slide" ng-class="getSlideClass(chunkSize)" smart-chunking>

The controller contains a map of classes that map to chunk sizes:

var classMap = {
  5: 'col-sm-2',
  4: 'col-sm-3',
  3: 'col-sm-4',
  2: 'col-sm-5',
};

$scope.getSlideClass = function(chunkSize) {
  if (classMap[chunkSize]) {
    return classMap[chunkSize];
  } else {
    return 'col-sm-10';
  }
}

I did find that adding some CSS made things look quite a bit better.

.carousel-caption {
  padding-bottom: 0;
}

.carousel-control.left,
.carousel-control.right {
  background-image: none;
}

.carousel-indicators {
  display: none;
}

.carousel-inner {
  padding-left: 10%;
  overflow: visible;
}

.carousel-control .glyphicon-chevron-left,
.carousel-control .glyphicon-chevron-right {
  font-size: 100px;
  margin-top: -60px;
  font-style: normal;
  font-weight: 100;
}

.carousel-control .glyphicon-chevron-left {
  margin-left: -100px;
}

.carousel-control .glyphicon-chevron-right {
  margin-right: -40px;
}

/* make slide widths more responsive */
@media only screen and (min-width: 1600px) {
  .col-sm-2 {
    width: 18%;
  }
}

@media only screen and (min-width: 1200px) {
  .col-sm-3 {
    width: 22%;
  }
  .carousel-control .glyphicon-chevron-left {
    margin-left: -70px;
  }
  .carousel-control .glyphicon-chevron-right {
    margin-right: -20px;
  }
}

@media only screen and (max-width: 1200px) {
  .col-sm-4 {
    width: 29%;
  }
  .carousel-control .glyphicon-chevron-left {
    margin-left: -70px;
  }
  .carousel-control .glyphicon-chevron-right {
    margin-right: -20px;
  }
}

@media only screen and (max-width: 800px) {
  .col-sm-10 {
    width: 90%;
  }
}

I hope this tip helps you if you need to implement a similar feature. I've published a demo on Plunkr (best experienced in embedded view).

Image title


Create data driven applications in Qlik’s free and easy to use coding environment, brought to you in partnership with Qlik.

Topics:
angularjs ,javascript ,chunking ,carousel ,bootstrap

Published at DZone with permission of Matt Raible, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}