Q:

Angular / javascript product filter

I want to modify this product angular / javascript filter 
When user select for example: Processor - 2GHz and Memory - 32GB I want to show only product that have all those properties.
Right now filter shows all products with 2GHz and all products with 32GB.
Plunker
https://plnkr.co/edit/vr9o2aHkHvCL1cvgKILd?p=preview

    angular.module('app', [])
      .controller('Controller', function($scope) {
        $scope.items = [{
          "name": "Product - 2GHZ, 32GB, Black",
          "tags": [{
            "category": 1,
            "tag": 2
          }, {
            "category": 2,
            "tag": 4
          }, {
            "category": 3,
            "tag": 8
          }]
        }, {
          "name": "Product - 2GHz, 128GB, Black",
          "tags": [{
            "category": 1,
            "tag": 2
          }, {
            "category": 2,
            "tag": 5
          }, {
            "category": 3,
            "tag": 8
          }]
        }, {
          "name": "Product - 1GHz, 128GB, White",
          "tags": [{
            "category": 1,
            "tag": 1
          }, {
            "category": 2,
            "tag": 5
          }, {
            "category": 3,
            "tag": 7
          }]
        }];

        $scope.items_dup = $scope.items
          // checkbox selection
        $scope.selectionTag = [];
        $scope.selectionCat = [];
        $scope.toggleSelection = function toggleSelection(tag, category) {
          var idxTag = $scope.selectionTag.indexOf(tag);
          if (idxTag > -1) {
            $scope.selectionTag.splice(idxTag, 1);
          } else {
            $scope.selectionTag.push(tag);
          }
          // this is not working, probably need twodimensional array
          // category
          var idxCat = $scope.selectionCat.indexOf(category);
          if (idxCat > -1) {
            $scope.selectionCat.splice(idxCat, 1);
          } else {
            $scope.selectionCat.push(category);
          }
        };

        // filter list
        $scope.filter = function() {
          filterTag($scope.selectionTag, $scope.items);

          function filterTag(selected, items) {
            var out = [];
            angular.forEach(items, function(value, key) {
              angular.forEach(selected, function(inner_value, key) {
                angular.forEach(value.tags, function(inner_value2, key) {
                  if (value.tags[key].tag === inner_value) {
                    if (out.indexOf(value) == -1) {
                      out.push(value)
                    }
                  }
                })
              })
            })
            if (out.length > 0) {
              $scope.items_dup = out;
            } else {
              $scope.items_dup = $scope.items;
            }
          }

        };
      })
<!DOCTYPE html>
<head>
  <script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.min.js"></script>
  <script src="script.js"></script>
</head>
<body ng-app="app">
  <div ng-controller="Controller">
    <h1>Product filtering!</h1>
    <li ng-repeat="item in items_dup">
      {{item.name}}
    </li>
    <hr>
    <p data-category="1">Processor</p>
    <label>
      <input type="checkbox" value="1" ng-click="toggleSelection(1,1)"> 1GHz
    </label>
    <br>
    <label>
      <input type="checkbox" value="2" ng-click="toggleSelection(2,1)"> 2GHz
    </label><br>
    <hr>
    <p data-category="2">Memory</p>
    <label>
      <input type="checkbox" value="4" ng-click="toggleSelection(4,2)"> 32GB
    </label>
    <br>
    <label>
      <input type="checkbox" value="5" ng-click="toggleSelection(5,2)"> 128GB
    </label><br>
    <hr>
    <p data-category="3">Color</p>
    <label>
      <input type="checkbox" value="7" ng-click="toggleSelection(7,3)"> White
    </label>
    <br>
    <label>
      <input type="checkbox" value="8" ng-click="toggleSelection(8,3)"> Black
    </label><br>
    <br><br>
    <button ng-click="filter()">Filter list</button>
  </div>
</body>
</html>

A:

You could use Array#every to check if each selection appears in an item's tag list. If you want to switch back from an and to an or filter, you can use Array#some instead.
The good thing about these methods is that they return as soon as they know their result, ending the loop early when possible.
$scope.filter = function() {
  $scope.items_dup = $scope.items.filter(function(item) {
    return $scope.selectionCat.every(function(c) {
      return item.tags
        .some(function(t) {
          return t.category === c &&
            $scope.selectionTag.indexOf(t.tag) !== -1;
        });
    })

  });
}

In a plunker: here
An example of how you could create a map, and how it would affect your filter:
var $scope.items = [ /* ... */ ].map(function(item) {
  var tagMap = item.tags.reduce(function(result, t.tag) {
    result[t.tag] = true; // Add the tag Id to the map
    return result;
  }, {});

  // Add the tag map to the item
  return Object.assign(item, { tagMap: tagMap });

});

// Now, you can filter like so:
var matches = selectedTagIds.every(function(id) {
  return item.tagMap[id];
});

