Search code examples
angularjsangularjs-ng-repeatangularjs-filtercascadingdropdown

AngularJS Changing DropDowns according to DropDown Values for ng-repeat filters


I have a list of about 1400 locations around the world and displaying them using ng-repeat. I want to have dropdowns to narrow the list down using the filter feature so I can only see locations in Region: Americas, Country:Canda for example. I have gotten the dropdown filters to work properly but my issue is changing the values of the dropdowns. If I select the Region option in the first dropdown, the country dropdown should only have countries in that Region.

Here is my Template:

Region:<select ng-model='RegionLocation.Region' ng-options="location.Region for location in RegionOptions.Regions"></select>
Country:<select ng-model='CountryLocation.Country' ng-options="location.Country for location in CountryOptions.Countries"></select>
<div>
    <md-card data-ng-repeat="location in LocationCtrl.Locationlist | filter:RegionFilter | filter:CountryFilter ">
        <md-card-content>
            <h2>{{::location.LID}}</h2>
        </md-card-content>
    </md-card>
</div>

Here is my Controller.js

function LocationController(LocationList, $scope) {
    var LocationCtrl = this;

    LocationCtrl.Locationlist = LocationList;

    LocationCtrl.Regions = filterRegions(LocationList);
    LocationCtrl.Regions.unshift({
        Region: 'Show All'
    })
    $scope.RegionOptions = {
        Regions:LocationCtrl.Regions,
    }
    $scope.RegionLocation = {
        Region: $scope.RegionOptions.Regions[0],
    }
    $scope.CountryOptions = {
        Countries:getCountries()
    };
    $scope.CountryLocation = {
        Country: $scope.CountryOptions.Countries[0]
    };
    $scope.RegionFilter = function (data) {
        if($scope.RegionLocation.Region.Region == 'Show All'){
            return true;
        } else if(data.Region == $scope.RegionLocation.Region.Region){
            return true;
        } else{
            return false;
        }
    };
    $scope.CountryFilter = function (data) {
        if($scope.CountryLocation.Country.Country == 'Show All'){
            return true;
        } else if(data.Country == $scope.CountryLocation.Country.Country){
            return true;
        } else{
            return false;
        }
    };
    function getCountries(){
        LocationCtrl.Countries = filterCountries(LocationList);
        LocationCtrl.Countries.unshift({
            Country: 'Show All'
        });
        return LocationCtrl.Countries;
    };
    function filterRegions(arr) {
      var f = []
      return arr.filter(function(n) {
        return f.indexOf(n.Region) == -1 && f.push(n.Region)
      })
    };
    function filterCountries(arr){
        var f = [];
        return arr.filter(function(n) {
            return f.indexOf(n.Country) == -1 && f.push(n.Country)
        })
    };

}

I also understand my code is not super clean nor simple so suggestions to simplify it are more than welcome.

Thank you!!


Solution

  • You were on the right track with using a filter on the ng-repeat, here is how I managed to get it working based of some mock data. Its really simple to get this done using a filter. I hope this helps.

    var app = angular.module('plunker', []);
    
    app.controller('MainCtrl', function($scope, $filter) {
      $scope.name = 'Sup World';
    
      $scope.list = [{
        "LID": "AB02",
        "City": "Calgary",
        "State": "Alberta",
        "Country": "Canada",
        "Region": "Americas",
        "Latitude": "XXXXXX",
        "Longitude": "XXXXX"
      }, {
        "LID": "AB08",
        "City": "Canmore",
        "State": "Alberta",
        "Country": "Canada",
        "Region": "Americas",
        "Latitude": "XXXXXX",
        "Longitude": "XXXXXXX"
      }, {
        "LID": "AB09",
        "City": "Cape Town",
        "State": "Western Cape",
        "Country": "South Africa",
        "Region": "Africa",
        "Latitude": "XXXXXX",
        "Longitude": "XXXXXXX"
      }, {
        "LID": "AB12",
        "City": "Eish",
        "State": "Somewhere",
        "Country": "Zimbabwe",
        "Region": "Africa",
        "Latitude": "XXXXXX",
        "Longitude": "XXXXX"
      }, {
        "LID": "AB18",
        "City": "Lusaka",
        "State": "Zambia?",
        "Country": "Zambia",
        "Region": "Africa",
        "Latitude": "XXXXXX",
        "Longitude": "XXXXXXX"
      }, {
        "LID": "AB19",
        "City": "Durban",
        "State": "Kwazulu Natal",
        "Country": "South Africa",
        "Region": "Africa",
        "Latitude": "XXXXXX",
        "Longitude": "XXXXXXX"
      }, {
        "LID": "AB13",
        "City": "Pretoria",
        "State": "JoJo",
        "Country": "South Africa",
        "Region": "Africa",
        "Latitude": "XXXXXX",
        "Longitude": "XXXXXXX"
      }];
    
      $scope.region = [];
      //get unique regions
      $scope.regions = $filter('unique')($scope.list, "Region");
    
      $scope.country = [];
      //get unique countries
      $scope.countries = $filter('unique')($scope.list, "Country");
    
    });
    
    app.filter('unique', function() {
      return function(arr, field) {
        var o = {},
          i, l = arr.length,
          r = [];
        for (i = 0; i < l; i += 1) {
          o[arr[i][field]] = arr[i];
        }
        for (i in o) {
          r.push(o[i]);
        }
        return r;
      };
    })
    <!DOCTYPE html>
    <html ng-app="plunker">
    
    <head>
      <meta charset="utf-8" />
      <title>AngularJS Plunker</title>
      <script>
        document.write('<base href="' + document.location + '" />');
      </script>
      <link rel="stylesheet" href="style.css" />
      <script data-require="angular.js@1.4.x" src="https://code.angularjs.org/1.4.12/angular.js" data-semver="1.4.9"></script>
      <script src="app.js"></script>
    </head>
    
    <body ng-controller="MainCtrl">
      Region:
      <select ng-model='region' ng-options="location.Region for location in regions"></select> 
    Country: 
    <select ng-model='country' ng-options="location.Country for location in countries | filter:{'Region': region.Region }"></select>
      <div>
        <md-card data-ng-repeat="location in list | filter:{'Region':region.Region,'Country':country.Country} ">
          <md-card-content>
            <h2>{{::location.LID}}</h2>
          </md-card-content>
        </md-card>
      </div>
    </body>
    
    </html>