AngularJS not filtering products list

2019-09-02 08:49发布

I am having an issue with AngularJS filtering my products list. I have done a few console.log queries on my variables and all seem fine. The problem is that the view does not update to show the filtered products.

Filtering works perfectly fine when you enter the search text in the input box but it does not work when clicking on the Category menu items.

I would like to filter the product list by category when the user clicks on the menu item.

Please see my code below and any help or advice is greatly appreciated.

My app.js

myApp.controller('StoreController', function($scope, $filter, storeFactory, cartFactory) {
  $scope.cartTotal = 0;
  $scope.cartItems = [];
  $scope.categories = [];
  $scope.counted = 0;
  $scope.filteredProducts = {};

  //get the products
  storeFactory.getProducts(function(results) {
    $scope.products = results.products;
    $scope.counted = $scope.products.length;
    $scope.filteredProducts = results.products; 
  });

  $scope.$watch("search", function(query){
    if($scope.filteredProducts.length) { 
      $scope.filteredProducts = $filter("filter")($scope.products, query);
      $scope.counted = $scope.filteredProducts.length; 
    }
  });

  $scope.filterProductsByCategory = function(categoryName){
    console.log('category filter');
    /*$scope.products.forEach(function(o,i){
      console.log('filter');
      if( o.category_id !== categoryId ){
       $scope.filteredProducts.splice(i,1);
       console.log('removing');
       console.log(o);
      }
    });*/
    $scope.filteredProducts = $filter("filter")($scope.filteredProducts, categoryName);
    console.info('the filtered items');
    console.log($scope.filteredProducts);
    $scope.counted = $scope.filteredProducts.length;
  } 

  $scope.getCategories = function(){
    storeFactory.getCategories(function(results){
      $scope.categories = results.rows; 
    });
  }

      $scope.getCategories();
});

My store.htm

UPDATE : I removed the extra controller reference and wrapped everything in one div.

<div ng-controller="StoreController">

      <!-- the sidebar product menu -->
       <div class="block-content collapse in">
        <div class="daily" ng-repeat="category in categories | orderBy:'name'">
          <div class="accordion-group">
            <div ng-click="filterProductsByCategory(category.category_name)" class="accordion-toggle collapsed">{{category.category_name}}</div>
          </div>
        </div>
      </div>    
      </div>

      <!-- Load store items start -->
        <div class="label">Showing {{counted}} Product(s)</div> 
        <div class="row" ng-repeat="product in filteredProducts | orderBy:'product_name'" style="margin-left: 0px; width: 550px;">
          <hr></hr>
          <div class="span1" style="width: 120px;">

            <!--         <a data-toggle="lightbox" href="#carouselLightBox"> -->
            <a data-toggle="lightbox" href="#carouselLightBox{{product.product_id}}">
            <!--img alt={{ product.product_name }} ng-src="{{product.image}}" src="{{product.image}}" /-->
                <img id="tmp" class="" src="images/products/{{product.product_image_filename}}" alt=""></img>
            </a>
            <div class="lightbox hide fade" id="carouselLightBox{{product.product_id}}" style="display: none;">
              <div class='lightbox-content'>
                <img src="images/products/{{product.product_image_filename}}" alt="" />
                  <!--img alt={{ product.product_name }} ng-src="{{product.image}}" src="{{product.image}}" /-->
                  <button class="btn btn-primary" id="close_lightbox"  ng-click="closeBox(product.product_id, $event)">Close</button>
              </div>
                <style>
                  #close_lightbox
                  {
                    position: absolute;
                    top: 5px;
                    right: 5px;
                  }
                </style>
            </div>
          </div>

          <div class="span6" style="width: 330px; margin-bottom: 15px;">
            <h5 style="font-size: 14px; font-weight: bold;">{{product.product_name}}</h5>
            <p>{{product.product_description }}</p>
            <p>Category : {{product.category_name}}</p>
          </div>
          <div class="span3">
            <p class="price">Price : <strong>R{{ product.product_price }}</strong></p>
              </div>
        </div>

    <!-- end of controller -->
    </div>

2条回答
三岁会撩人
2楼-- · 2019-09-02 08:55
$scope.filteredProducts = {};

//get the products
storeFactory.getProducts(function (results) {
    $scope.products = results.products;
    $scope.counted = $scope.products.length;
    $scope.filteredProducts = results.products;
});

Is results.products an array of objects or an object of objects? Because $filter('filter')($scope.products,query); expects $scope.products to be an array.

$scope.$watch("search", function (query) {
    if($scope.filteredProducts.length) {
        $scope.filteredProducts = $filter("filter")($scope.products, query);
        $scope.counted = $scope.filteredProducts.length;
    }
});

Here's what I'm thinking this should look like and you won't need the $watch statement or the filteredProducts array/object, In controller:

$scope.search = '';
$scope.products = [];
$scope.categories = ['category1','category2','category3'];

// assuming that your store function getProducts returns a promise here
storeFactory.getProducts().then(function(results){
    $scope.products = results.products; // needs to be an array of product objects
});

$scope.filterProductsByCategory = function(category){
    $scope.search = category;
};

Then in your HTML Partial, this is not exactly how your's is, I'm just showing you here in shorter form what is possible:

<button ng-repeat="cat in categories" ng-click="filterProductsByCategory(cat)">{{cat}}</button>

<div class="row" ng-repeat="product in products | filter:search | orderBy:'product_name'">
    <!-- Product Information Here -->
</div>

I created a JSFiddle to demonstrate: http://jsfiddle.net/mikeeconroy/QL28C/1/ You can free form search with any term or click a button for a category.

查看更多
Fickle 薄情
3楼-- · 2019-09-02 09:10

The side bar is using one instance of StoreController, and the main div is using another instance of StoreController. Each instance having its own scope. The should both use the same controller instance: wrap everything inside a div, and use a unique StoreController for this wrapping div.

查看更多
登录 后发表回答