AngularJS:按位置过滤

时间:2015-11-05 17:39:26

标签: json angularjs google-maps angular-filters

我有一个SPA,它使用选择列表按地区,州/省/欧盟国家/地区,城市过滤到某个位置。

我有一些过滤工作,但对于我的位置lat / lng值(最终将为Google Maps小部件供电),它无法正常工作。我没有在Region之外进行过滤,甚至在Region上,我得到的是不属于所选区域的位置。

var app = angular.module('plunker', ['angular.filter']);

app.controller('MainCtrl', function($scope, $anchorScroll, $location, $http) {

  $scope.cart = [];

  $scope.addToCart = function(index) {
    $scope.cart.push(index);

    $scope.cartCount = $scope.cart.length;
  }



  $scope.activeRow = function(index) {
    $scope.selectedRow = index;

    $location.hash();
    $anchorScroll('anchor-' + index);

  }


  $scope.gotoAnchor = function(x) {
    var newHash = 'anchor' + x;


  }

  // GET data
        $scope.dataObject = data.List;
        $scope.locationObject = data.Locations;

}).filter('byCountry', function() {

  return function(items, location) {
    var filtered = [];

    if (!location || !items.length) {
      return items;
    }

    items.forEach(function(itemElement, itemIndex) {
      itemElement.Locations.forEach(function(locationElement, locationIndex) {
        if (locationElement.Region === location.Region) {
          filtered.push(itemElement);
          return false;
        }
      });
    });

    return filtered;
  };
}).filter('byRegion', function() {

  return function(items, location) {
    var filtered = [];

    if (!location || !items.length) {
      return items;
    }

    items.forEach(function(itemElement, itemIndex) {
      itemElement.Locations.forEach(function(locationElement, locationIndex) {
        locationElement.Sites.forEach(function(siteElement, siteIndex) {
          if (siteElement.State === location.StateName) {
            filtered.push(itemElement);
            return false;
          }
        });
      });
    });

    return filtered;
  };
}).filter('byCity', function() {

  return function(items, location) {
    var filtered = [];

    if (!location || !items.length) {
      return items;
    }

    items.forEach(function(itemElement, itemIndex) {
      itemElement.Locations.forEach(function(locationElement, locationIndex) {
        locationElement.Sites.forEach(function(siteElement, siteIndex) {
          if (siteElement.City === location.CityName) {
            filtered.push(itemElement);
            return false;
          }
        });
      });
    });

    return filtered;
  };
}).filter('ForMap', function() {

  return function(items, location) {
    var filtered = [];

    if (!location || !items.length) {
      return items;
    }

    items.forEach(function(itemElement, itemIndex) {
      itemElement.Locations.forEach(function(locationElement, locationIndex) {
        if (locationElement.Region === location.Region) {
          filtered.push(itemElement);
          return false;
        }
        locationElement.Sites.forEach(function(siteElement, siteIndex) {
          if (siteElement.State === location.StateName || siteElement.City === location.CityName) {
            filtered.push(itemElement);
            return false;
          }
        });
      });
    });

    return filtered;
  };

});
body {
  background: #eee;
}
div.cart {
  display: block;
  height: 70px;
  background: silver;
  margin-left: 20px;
  width: 200px;
  padding: 5px 10px;
  margin-bottom: 20px;
  margin-top: 20px;
}
.cart h1 {
  color: #fff;
  line-height: 20px;
}
.item-list-wrapper {
  height: 400px;
  width: 90%;
  border: 1px solid #ddd;
  overflow-y: scroll;
  margin-left: 20px;
}
.item-list-wrapper table td {
  padding: 10px;
  vertical-align: middle;
  margin-bottom: 10px;
  font-size: 12px;
}
.item-list {
  height: auto;
  width: 100%;
  margin-bottom: 10px;
  box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2);
  border: 1px solid #fff;
  background: #efefe4;
}
.col-num {
  width: 100px;
}
.col-compound {
  width: 80px;
}
.filters {
  width: 100%;
  clear: both;
  margin-left: 20px;
}
.filters select {
  width: 200px;
}
.filters column {
  height: 100px;
  width: 200px;
  display: inline-block;
  margin: 0;
  padding: 0;
}
.filters select {
  display: inline-block;
}
.region {
  font-weight: bolder;
}
.state {
  font-weight: normal;
}
<!DOCTYPE html>
<html ng-app="plunker">

<head>
  <meta charset="utf-8" />
  <title>AngularJS Plunker</title>
  <link data-require="bootstrap@*" data-semver="3.3.5" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" />
  <link data-require="bootstrap-css@*" data-semver="3.3.1" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />

  <link rel="stylesheet" href="angular-ui.min.css" />

  <script>
    document.write('<base href="' + document.location + '" />');
  </script>
  <link rel="stylesheet" href="style.css" />
  <script data-require="angular.js@1.4.x" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.7/angular.min.js" data-semver="1.4.7"></script>
        <script data-require="angular.js@1.4.x" data-semver="1.4.7" src="https://code.angularjs.org/1.4.7/angular-messages.js"></script>
        <script data-require="ui-bootstrap@*" data-semver="0.13.3" src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.13.1/ui-bootstrap.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-filter/0.5.7/angular-filter.min.js"></script>
        <script src="angular-ui.min.js"></script>
        <script src="app.js"></script>
        <script src="http://zbl.me/test/103015.js"></script>

</head>

<body ng-controller="MainCtrl">
  <div ng-view=""></div>



  <!--item-list-wrapper -->

  <div class="filters">
    <h2>Filter results</h2>
    <column>
      <select name="selectRegion" class="form-control" ng-model="selectRegion" ng-change="europeSelected()" ng-options="location as location.Region for location in locationObject | orderBy: location.Region:reverse">
        <option value="">Select Region</option>
      </select>

      <select name="selectState" class="form-control" ng-disabled="!selectRegion" ng-model="selectState" ng-options="state as state.StateName for state in selectRegion.States">
        <option value="">Select State/Province/Country</option>
      </select>

      <select name="selectCity" class="form-control" ng-disabled="!selectState" ng-model="selectCity" ng-options="city as city.CityName for city in selectState.Cities">
        <option value="">Select City</option>
      </select>
    </column>
    <column>
      <select name="selectPhase" class="form-control" ng-model="selectPhase" ng-options="data.Phase as data.Phase for data in dataObject | unique: 'Phase' | orderBy: 'Phase' ">
        <option value="">Select Phase</option>
      </select>
      <select name="selectNumber" class="form-control" ng-model="selectNumber" ng-options="data.Number as data.Number for data in dataObject | unique: 'Compound' | orderBy: 'Compound' ">
        <option value="">Select Number</option>
      </select>
    </column>


  </div>



  <div class="cart">
    <h1>Cart: {{cartCount}}</h1>
  </div>


  <div class="item-list-wrapper">
    <table class="table table-condensed table-hover">
      <tr ng-repeat="data in dataObject | byCountry : selectRegion | byRegion : selectState | byCity : selectCity | filterBy:['Phase']: selectPhase | filterBy:['Number']: selectNumber track by $index" ng-click="activeRow($index)">
        <td class="column">{{data.Phase}}</td>
        <td class="column col-num">{{data.Number}}</td>
        <td class="column col-compound">{{data.Compound}}</td>
        <td>
          <span ng-repeat="location in data.Locations track by $index" class="region">{{ location.Region}}: 
  				<span ng-repeat="site in location.Sites | unique: 'State'" class="state">{{site.State}}
					</span>
          </span>
        </td>
        <td><a href="" ng-click="addToCart()">Add</a>
        </td>
      </tr>
    </table>
  </div>

  <!-- lat lng debugging -->
  <div style="width: 100%; height: 400px; position: absolute; bottom: 0; left: 0; background: rgba(255,255,255,0.9); z-index: 1000; padding: 10px; overflow-y:scroll; border-left: 5px solid black; border-right: 5px solid black">
    <h3>filtered lat/lng values</h3>

    <span ng-repeat="data in dataObject | ForMap : selectRegion | ForMap : selectState | ForMap : selectCity ">

					<span class="trials-item-cell">
						<span ng-repeat="location in data.Locations track by $index" class="region">
		                <span ng-repeat="site in location.Sites | unique: 'State'" class="state">{{site.City}}: [{{site.Latitude}},{{site.Longitude}}]<span ng-show=" ! $last ">, </span>
    </span>
    </span>
    </span>


    </span>

  </div>



</body>

</html>

Plunkr:http://plnkr.co/edit/LKcFhG?p=preview

1 个答案:

答案 0 :(得分:1)

编辑1

您不使用track by:

排队:

<span ng-repeat="data in dataObject | ForMap : selectRegion | ForMap : selectState | ForMap : selectCity">

按以下方式添加曲目:

<span ng-repeat="data in dataObject | ForMap : selectRegion | ForMap : selectState | ForMap : selectCity track by $index">

编辑2

var app = angular.module('plunker', ['ngRoute','angular.filter', 'ngMap']);

app.controller('MainCtrl', function($scope, $anchorScroll, $location, $http) {

    $scope.cart = [];

    $scope.addToCart = function(index) {
        $scope.cart.push(index);
        $scope.cartCount = $scope.cart.length;
    }

    $scope.activeRow = function(index) {
        $scope.selectedRow = index;
        $location.hash();
        $anchorScroll('anchor-' + index);
    }

    $scope.gotoAnchor = function(x) {
        var newHash = 'anchor' + x;
    }

    // GET data
    $http({
        method: 'GET',
        url: '103015.json'
    }).then(function successCallback(response) {
        $scope.dataObject = response.data.List;
        $scope.locationObject = response.data.Locations;

    }, function errorCallback(response) {
        alert('error');
    });


}).filter('byFilter', function(){
    return function(items, location) {
        var filtered = [];

        if (!location || !items.length) {
            return items;
        }

        items.forEach(function(itemElement, itemIndex) {
            itemElement.Locations.forEach(function(locationElement, locationIndex) {
                if(filterCountry(locationElement, location) || filterRegion(locationElement, location) || filterCity(locationElement, location))
                filtered.push(itemElement);
            });
        });

        return filtered;
    };

    function filterCountry(locationElement, location){
        var exist = false;
        if(!location.Region){
            exist = true;
            return exist;
        }else exist = (locationElement.Region === location.Region);
        return exist;
    }

    function filterRegion(locationElement, location){
        var exist = false;
        if(!location.StateName){
            exist = true;
            return exist;
        }
        locationElement.Sites.forEach(function(siteElement, siteIndex) {
            if (siteElement.State === location.StateName) {
                exist = true;
                return false;
            }
        });
        return exist;
    }

    function filterCity(locationElement, location){
        var exist = false;
        if(!location.CityName){
            exist = true;
            return exist;
        }

        locationElement.Sites.forEach(function(siteElement, siteIndex) {
            if (siteElement.City === location.CityName) {
                exist = true;
                return false;
            }
        });
        return exist;
    }
}).filter('ForMap', function(){
    return function(items, location) {
        var filtered = [];

        if (!location || !items) {
            return items;
        }

        var state = (location.state? location.state.StateName:'');
        var city = (location.city? location.city.CityName:'');
        var region = (location.region? location.region.Region:'');

        items.forEach(function(itemElement, itemIndex) {
            itemElement.Locations.forEach(function(locationElement, locationIndex) {
                if (locationElement.Region === region) {
                    locationElement.Sites.forEach(function(siteElement, siteIndex) {
                        console.log(siteElement.State + ' > ' + state + ' | ' + siteElement.City + ' > ' + city);
                        if ((siteElement.State == state && !city) || siteElement.City == city) {
                            filtered.push(itemElement);
                            return false;
                        }
                    });
                }
            });
        });
        return filtered;
    };
});


<!DOCTYPE html>
<html ng-app="plunker">
    <head>
        <meta charset="utf-8" />
        <title>AngularJS Plunker</title>
        <link data-require="bootstrap@*" data-semver="3.3.5" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" />
        <link data-require="bootstrap-css@*" data-semver="3.3.1" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />
        <link rel="stylesheet" href="angular-ui.min.css" />
        <script>
        document.write('<base href="' + document.location + '" />');
        </script>
        <link rel="stylesheet" href="style.css" />
        <script data-require="angular.js@1.4.x" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.7/angular.min.js" data-semver="1.4.7"></script>
        <script data-require="angular.js@1.4.x" data-semver="1.4.7" src="https://code.angularjs.org/1.4.7/angular-messages.js"></script>
        <script data-require="ui-bootstrap@*" data-semver="0.13.3" src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.13.1/ui-bootstrap.min.js"></script>
        <script src="angular-filter.min.js"></script>
        <script src="angular-route.min.js"></script>
        <script src="ng-map.min.js"></script>
        <script src="angular-ui.min.js"></script>
        <script src="angular-scroll.min.js"></script>
        <script src="app.js"></script>
    </head>
    <body ng-controller="MainCtrl">
        <div ng-view=""></div>
        <div class="filters">
            <h2>Filter results</h2>
            <column>
                <select name="selectRegion" class="form-control" ng-model="selectRegion" ng-change="europeSelected()" ng-options="location as location.Region for location in locationObject | orderBy: location.Region:reverse">
                    <option value="">Select Region</option>
                </select>

                <select name="selectState" class="form-control" ng-disabled="!selectRegion" ng-model="selectState" ng-options="state as state.StateName for state in selectRegion.States">
                    <option value="">Select State/Province/Country</option>
                </select>

                <select name="selectCity" class="form-control" ng-disabled="!selectState" ng-model="selectCity" ng-options="city as city.CityName for city in selectState.Cities">
                    <option value="">Select City</option>
                </select>
            </column>
            <column>
                <select name="selectPhase" class="form-control" ng-model="selectPhase" ng-options="data.Phase as data.Phase for data in dataObject | unique: 'Phase' | orderBy: 'Phase' ">
                    <option value="">Select Phase</option>
                </select>
                <select name="selectNumber" class="form-control" ng-model="selectNumber" ng-options="data.Number as data.Number for data in dataObject | unique: 'Compound' | orderBy: 'Compound' ">
                    <option value="">Select Number</option>
                </select>
            </column>
        </div>
        <div class="cart">
            <h1>Cart: {{cartCount}}</h1></div>
            <div class="item-list-wrapper">
                <table class="table table-condensed table-hover">
                    <tr ng-repeat="data in dataObject | byFilter | filterBy:['Phase']: selectPhase | filterBy:['Number']: selectNumber track by $index" ng-click="activeRow($index)">
                        <td class="column">{{data.Phase}}</td>
                        <td class="column col-num">{{data.Number}}</td>
                        <td class="column col-compound">{{data.Compound}}</td>
                        <td>
                            <span ng-repeat="location in data.Locations track by $index" class="region">{{ location.Region}}: 
                                <span ng-repeat="site in location.Sites | unique: 'State'" class="state">{{site.State}}
                                </span>
                            </span>
                        </td>
                        <td><a href="" ng-click="addToCart()">Add</a></td>
                    </tr>
                </table>
            </div>

            <!-- lat lng debugging -->
            <div style="width: 100%; height: 400px; position: absolute; bottom: 0; left: 0; background: rgba(255,255,255,0.9); z-index: 1000; padding: 10px; overflow-y:scroll; border-left: 5px solid black; border-right: 5px solid black">
                <h3>filtered lat/lng values</h3>
                <span ng-repeat="data in (dataObject | ForMap : {region:selectRegion, state:selectState, city:selectCity}) track by $index">
                    <span class="trials-item-cell">
                        <span ng-repeat="location in data.Locations track by $index" class="region">
                            <span ng-repeat="site in location.Sites | unique: 'State'" class="state">{{site.City}}: [{{site.Latitude}},{{site.Longitude}}]<span ng-show=" ! $last ">, </span>
                        </span>
                    </span>
                </span>
            </span>
        </div>
    </body>
</html>

编辑3

var app = angular.module('plunker', ['ngRoute','angular.filter', 'ngMap']);

app.controller('MainCtrl', function($scope, $anchorScroll, $location, $http) {

    $scope.cart = [];

    $scope.addToCart = function(index) {
        $scope.cart.push(index);
        $scope.cartCount = $scope.cart.length;
    }

    $scope.activeRow = function(index) {
        $scope.selectedRow = index;
        $location.hash();
        $anchorScroll('anchor-' + index);
    }

    $scope.gotoAnchor = function(x) {
        var newHash = 'anchor' + x;
    }

    // GET data
    $http({
        method: 'GET',
        url: '103015.json'
    }).then(function successCallback(response) {
        $scope.dataObject = response.data.List;
        $scope.locationObject = response.data.Locations;

    }, function errorCallback(response) {
        alert('error');
    });


}).filter('byFilter', function(){
    return function(items, location) {
        var filtered = [];

        if (!location || !items.length) {
            return items;
        }

        items.forEach(function(itemElement, itemIndex) {
            itemElement.Locations.forEach(function(locationElement, locationIndex) {
                if(filterCountry(locationElement, location) || filterRegion(locationElement, location) || filterCity(locationElement, location))
                filtered.push(itemElement);
            });
        });

        return filtered;
    };

    function filterCountry(locationElement, location){
        var exist = false;
        if(!location.Region){
            exist = true;
            return exist;
        }else exist = (locationElement.Region === location.Region);
        return exist;
    }

    function filterRegion(locationElement, location){
        var exist = false;
        if(!location.StateName){
            exist = true;
            return exist;
        }
        locationElement.Sites.forEach(function(siteElement, siteIndex) {
            if (siteElement.State === location.StateName) {
                exist = true;
                return false;
            }
        });
        return exist;
    }

    function filterCity(locationElement, location){
        var exist = false;
        if(!location.CityName){
            exist = true;
            return exist;
        }

        locationElement.Sites.forEach(function(siteElement, siteIndex) {
            if (siteElement.City === location.CityName) {
                exist = true;
                return false;
            }
        });
        return exist;
    }
}).filter('ForMap', function(){
    return function(items, location) {
        var filtered = [];

        if (!location || !items) {
            return items;
        }

        var state = (location.state? location.state.StateName:'');
        var city = (location.city? location.city.CityName:'');
        var region = (location.region? location.region.Region:'');

        items.forEach(function(itemElement, itemIndex) {
            itemElement.Locations.forEach(function(locationElement, locationIndex) {
                if (locationElement.Region === region) {
                    locationElement.Sites.forEach(function(siteElement, siteIndex) {
                        console.log(siteElement.State + ' > ' + state + ' | ' + siteElement.City + ' > ' + city);
                        if ((siteElement.State == state && !city) || siteElement.City == city) {
                            filtered.push(siteElement);
                            return false;
                        }
                    });
                }
            });
        });
        return filtered;
    };
});
<!DOCTYPE html>
<html ng-app="plunker">
    <head>
        <meta charset="utf-8" />
        <title>AngularJS Plunker</title>
        <link data-require="bootstrap@*" data-semver="3.3.5" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" />
        <link data-require="bootstrap-css@*" data-semver="3.3.1" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />
        <link rel="stylesheet" href="angular-ui.min.css" />
        <script>
        document.write('<base href="' + document.location + '" />');
        </script>
        <link rel="stylesheet" href="style.css" />
        <script data-require="angular.js@1.4.x" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.7/angular.min.js" data-semver="1.4.7"></script>
        <script data-require="angular.js@1.4.x" data-semver="1.4.7" src="https://code.angularjs.org/1.4.7/angular-messages.js"></script>
        <script data-require="ui-bootstrap@*" data-semver="0.13.3" src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.13.1/ui-bootstrap.min.js"></script>
        <script src="angular-filter.min.js"></script>
        <script src="angular-route.min.js"></script>
        <script src="ng-map.min.js"></script>
        <script src="angular-ui.min.js"></script>
        <script src="angular-scroll.min.js"></script>
        <script src="app.js"></script>
    </head>
    <body ng-controller="MainCtrl">
        <div ng-view=""></div>
        <div class="filters">
            <h2>Filter results</h2>
            <column>
                <select name="selectRegion" class="form-control" ng-model="selectRegion" ng-change="europeSelected()" ng-options="location as location.Region for location in locationObject | orderBy: location.Region:reverse">
                    <option value="">Select Region</option>
                </select>

                <select name="selectState" class="form-control" ng-disabled="!selectRegion" ng-model="selectState" ng-options="state as state.StateName for state in selectRegion.States">
                    <option value="">Select State/Province/Country</option>
                </select>

                <select name="selectCity" class="form-control" ng-disabled="!selectState" ng-model="selectCity" ng-options="city as city.CityName for city in selectState.Cities">
                    <option value="">Select City</option>
                </select>
            </column>
            <column>
                <select name="selectPhase" class="form-control" ng-model="selectPhase" ng-options="data.Phase as data.Phase for data in dataObject | unique: 'Phase' | orderBy: 'Phase' ">
                    <option value="">Select Phase</option>
                </select>
                <select name="selectNumber" class="form-control" ng-model="selectNumber" ng-options="data.Number as data.Number for data in dataObject | unique: 'Compound' | orderBy: 'Compound' ">
                    <option value="">Select Number</option>
                </select>
            </column>
        </div>
        <div class="cart">
            <h1>Cart: {{cartCount}}</h1></div>
            <div class="item-list-wrapper">
                <table class="table table-condensed table-hover">
                    <tr ng-repeat="data in dataObject | byFilter | filterBy:['Phase']: selectPhase | filterBy:['Number']: selectNumber track by $index" ng-click="activeRow($index)">
                        <td class="column">{{data.Phase}}</td>
                        <td class="column col-num">{{data.Number}}</td>
                        <td class="column col-compound">{{data.Compound}}</td>
                        <td>
                            <span ng-repeat="location in data.Locations track by $index" class="region">{{ location.Region}}: 
                                <span ng-repeat="site in location.Sites | unique: 'State'" class="state">{{site.State}}
                                </span>
                            </span>
                        </td>
                        <td><a href="" ng-click="addToCart()">Add</a></td>
                    </tr>
                </table>
            </div>

            <!-- lat lng debugging -->
            <div style="width: 100%; height: 400px; position: absolute; bottom: 0; left: 0; background: rgba(255,255,255,0.9); z-index: 1000; padding: 10px; overflow-y:scroll; border-left: 5px solid black; border-right: 5px solid black">
                <h3>filtered lat/lng values</h3>
                <span ng-repeat="site in (dataObject | ForMap : {region:selectRegion, state:selectState, city:selectCity}) track by $index">
                    <span class="state">{{site.City}}: [{{site.Latitude}},{{site.Longitude}}]<span ng-show=" ! $last ">, </span>
                    </span>
                </span>
            </span>
        </div>
    </body>
</html>