Search code examples
javascripthtmlcssangularjsangularjs-scope

How to display the count of all items on click of a button in AngularJS?


I have say 9 items on a carousel.

I want to show the count of individual items below the the carousel images.

I have created a Plunker for demonstrating the issue.

Plunker Link

HTML CODE

<head>
<script data-require="[email protected]" data-semver="1.2.19" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.19/angular.min.js">
</script>
<script data-require="[email protected]" data-semver="2.1.1" src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="style.css" />
<link rel="stylesheet" href="http://vasyabigi.github.io/angular-slick/bower_components/slick-carousel/slick/slick.css" />
<script src="http://vasyabigi.github.io/angular-slick/bower_components/slick-carousel/slick/slick.js"></script>
<script src="angular-slick.js"></script>
<script src="script.js"></script>
</head>

<body ng-controller="appController">
<h1>Hello Plunker!</h1>
<button type="button" ng-click="showCount()">Show count of all items</button>

<slick ng-if="dataLoaded" init-onload="false" data="dataLoaded" slides-to-show="3" dots="true">
  <div ng-repeat="item in items">
    <span>
        <img ng-src="{{ item.imgSrc }}" alt="{{ item.catId}}" />
    </span>
    <span>{{ item.catId }}</span>
  </div>
</slick>

JS CODE

var app = angular.module("slick-example", ["slick"]);
app.controller('appController', function($scope, $timeout) {
    $scope.items = [];
    // simulate that the data is loaded from a remote source
    $timeout(function() {
        $scope.items = [{
            imgSrc: 'http://placekitten.com/325/325',
            catId: '1'
        }, {
            imgSrc: 'http://placekitten.com/g/325/325',
            catId: '2'
        }, {
            imgSrc: 'http://placekitten.com/325/325',
            catId: '3'
        }, {
            imgSrc: 'http://placekitten.com/g/325/325',
            catId: '4'
        }, {
            imgSrc: 'http://placekitten.com/325/325',
            catId: '5'
        }, {
            imgSrc: 'http://placekitten.com/g/325/325',
            catId: '6'
        }, {
            imgSrc: 'http://placekitten.com/325/325',
            catId: '7'
        }, {
            imgSrc: 'http://placekitten.com/g/325/325',
            catId: '8'
        }, {
            imgSrc: 'http://placekitten.com/325/325',
            catId: '9'
        }];
        $scope.countItem = [{
            "catId": 1,
            "availableCount": 2
        }, {
            "catId": 2,
            "availableCount": 3
        }, {
            "catId": 3,
            "availableCount": 4
        }, {
            "catId": 4,
            "availableCount": 2
        }, {
            "catId": 5,
            "availableCount": 1
        }, {
            "catId": 6,
            "availableCount": 5
        }, {
            "catId": 7,
            "availableCount": 3
        }, {
            "catId": 8,
            "availableCount": 2
        }, {
            "catId": 9,
            "availableCount": 1
        }];
        // update the dataLoaded flag after the data has been loaded
        // i dont know why but its important that the flag doesnt get initialized in an previous step like $scope.dataLoaded = false;
        $scope.dataLoaded = true;
    }, 2000);
    $scope.showCount = function() {}
});

When the button (button - Show count of individual items) is clicked I am trying to show the count of individual items below each image in carousel but I am not able to find a way to do so. On the click of the button count of all items is to be shown

Please refer the Plunker ( I am only using AngularJS and vanilla JS ,no Jquery )

Please help me how to show the count of individual items of the carousel just below each image


Solution

  • Here are two ways, second based on comment info.

    Version not modifying array

    This version waits until the data has "loaded", and then will create a map that will be used in the interpolated values of the count in your HTML.

    HTML

    This button will toggle the count on/off:

    <button type="button" ng-click="showCount = !showCount">Toggle Count</button>
    

    This goes where you want to display the count within the ng-repeat:

    <span ng-if="showCount">Count of Items: {{ countMap[$index] }}</span>
    

    For more on $index, review documentation on ng-repeat. Basically, it's telling you the index (location) in the array that the current repeated element is sourced from.

    JS

    In the root of your controller:

      // Create a mapping of array position : count
      $scope.countMap = {};
    

    This allows us to look up data later with ease. Ex:

    $scope.countMap1 = 'hello'; console.log($scope.countMap1); // -> hello

    Then, after your $timeout, once it has resolved (meaning timeout is reached, http request finished, etc):

    $timeout(function() {
       // Abbreviated, not including items.
    
      }, 2000).then(function() {
        // After resolve, assuming you are calling an API in real implementation
    
        // Iterate through the returned items, and add the count
        // to the array pos : count mapping
        for (var i = 0; i < $scope.items.length; i++) {
          $scope.countMap[i] = getCountFor($scope.items[i].catId);
        }
    
      });
    

    ** Also of note **, you set $scope.dataLoaded = true, but it is within the timeout. It should move into the .then(function() {} to ensure it's not set until the promise has resolved.

    And then, the original getCountFor(id) function from the modifying version below:

      function getCountFor(id) {
        for (var i = 0; i < $scope.countItem.length; i++) {
          if ($scope.countItem[i].catId == id) {
            return $scope.countItem[i].availableCount;
          }
        }
      }
    

    https://plnkr.co/edit/UOY7WONh6TUCBRrZYnvZ?p=preview

    Version modifying array

    This should do the trick. When you click "show count...", the function will iterate over each cat object in $scope.items, and call getCountFor(id) and append the availableCount value as found via relating the catId for the objects in each array.

    HTML

      <div ng-repeat="item in items">
        <span>
            <img ng-src="{{ item.imgSrc }}" alt="{{ item.catId}}" />
        </span>
        <span>{{ item.catId }}</span>
        <span> Count of Items: {{ item.availableCount }}</span>
      </div>
    

    JS

    This is a function used to separate the concerns of the code. It takes id as a parameter. It then increments i, starting at 0, and going until the value of i is the length of the $scope.countItem array. For each position in the array, there is an item. If the value of id passed to the function matches the value of catId for the object at position i of the array, the value of available count is returned.

      function getCountFor(id) {
        for (var i = 0; i < $scope.countItem.length; i++) {
          if ($scope.countItem[i].catId == id) {
            return $scope.countItem[i].availableCount;
          }
        }
      }
    

    This function is on $scope as it is called from your UI. When called, it iterates over each item in $scope.items, and sets a new property called availableCount on that item. It will render each item in $scope.items to look like this:

    {
        imgSrc: 'http://placekitten.com/325/325',
        catId: '1',
        availableCount: 0
    }
    

    And the actual showCount() function:

      $scope.showCount = function() {
        $scope.items.forEach(function(item) {
          item.availableCount = getCountFor(item.catId);
        })
      }
    

    https://plnkr.co/edit/2uLdLgVtsjbT6v4R0DWi?p=preview