Angularjs Cascading Dropdown/Select with demo

Angularjs onchange select Angularjs dropdown change event Angularjs dropdown menu Populate Dropdown 2 based on Dropdown 1 DropDownList Country-State-City Cascading How to Fill Country,State,Cities in the DropDownList Simple Example of dependable dropdowns angularjs dropdown default value

Cascading dropdown with angularjs is easier than MVC and ASP.Net. In Angularjs ng-change is the best event to hook the function to get the second dropdown list items. In this article, we will try to fill the state dropdown on selection change of country and then fill the city dropdown on change of state dropdown. We will fetch only those records from database which match the criteria rather than filtering in controller. I already create a codepen example so you can check it here

See the demo, here is the image of this example

alt text

I am going to use dummy json data which you can use the fetch the data from database, so you need to change the conde only in the service and not the controller and HTML, enough talked let's see the sevice methods to fetch the data

// Get Country list
service.getCountry = function(){    
    return countrylist;
};

// Get State list for country
service.getCountryState = function(countryId){
    var states = ($filter('filter')(statelist, {countryId: countryId}));
    return states;
};

// Get city list for state
service.getStateCity = function(stateId){   
    var items = ($filter('filter')(citylist, {stateId: stateId}));      
    return items;
};
  • countrylist, statelist and citylist are the list of json data
  • I try to get the data on the basis of Id
  • I used $filter to get data on the basis of Id

Let's say you are creating the customer page to add new customer or update existing customer so we need to keep that customer on the scope, if new a blank customer object on the scope and it's properties will be bind with ng-model. Since we need to show the country select list by default so we will get the complete list of country from service and put it on scope with name $scope.countries in our controller

myApp.controller('dropdownCtrl', ['$scope','CustomerService', 
  function($scope, CustomerService) {     
    $scope.customer ={
        Name:'', 
        Country:'', 
        State: '', 
        City: ''
    };

    $scope.countries = CustomerService.getCountry();   

}]);

Here I am creating the customer object manually, you can create an object directly from you class, like in Web API and return that like return new Customer();

Next I am calling the getCountry method in my service CustomerService which we already seen in above code. Now let's see the country dropdown in HTML and it's bindings

<select ng-model="customer.Country"                
    ng-options="obj.id as obj.country for obj in countries"
    ng-change="getCountryStates()"
    class="form-control" 
    ng-required="true"
    id="country">
    <option value="">-- Choose Country --</option>
</select>      
  • ng-model: which will bind the model country properties of customer
  • if existing customer, and have some value for country, it will automatically selected in the dropdown
  • ng-options: see how I bind to use the Id and show the country name in our countries list on scope
  • ng-required: true/false, to mark the control is required or not
  • I used some CSS to indicate the control status
  • Finally optional text "choose Country"
  • ng-change: is the event to fill the state list for selected country

So far it is good, nothing complicated, not on ng-change I am calling a method in controller to get the state list, doesn't have any parameter, so how we know which country is selected, note the ng-model which we already bind with customer country property, so we can use $scope.customer.Country, every time you change the country, country property in customer refreshed, see at the bottom where I am showing the selected values, here is the getCountryStates function

$scope.getCountryStates = function(){
    $scope.sates = CustomerService.getCountryState($scope.customer.Country);
    $scope.cities =[];
}
  • Every time country changes, we are fetching the state data and clearing the cities
  • Whatever I am getting from service, I put that on scope $scope.sates

Here is the state select HTML code

<select ng-model="customer.State" 
    ng-options="x.Id as x.state for x in sates"
    ng-change = "getStateCities()"
    class="form-control"
    ng-required="true"
    id="state">
    <option value="">-- Choose State --</option>
</select>    

It is very similar to country dropdown, it also contain ng-change event to fill the city by using getStateCities() function in controller

$scope.getStateCities = function(){   
    $scope.cities = CustomerService.getStateCity($scope.customer.State);
}

Again in the same way we are calling a service method to get the list of cities for selected state and put it on scope `$scope.cities' which we use to bind the cities in our view, here is the simplest city dropdown HTML

<select  ng-model="customer.City"
    ng-options="x.Id as x.city for x in cities"
    class="form-control" 
    ng-required="true"
    id="city">
    <option value="">-- Choose City --</option>
</select> 
  • It does not have any ng-change because we don't want to do anything on change of city
  • Every where I used Id property to combine the label and control otherwise you can omit it.

That's all we need for these three cascade dropdown, in HTML rest of the code is for designing the page and align the controls, all of the CSS and classes using the bootstrap. Here is the complete controller code:

angular.module("myApp")
 .controller('dropdownCtrl', ['$scope','CustomerService', 
   function($scope, CustomerService) {

    $scope.customer ={
        Name:'', 
        Country:'', 
        State: '', 
        City: ''
    };

    $scope.countries = CustomerService.getCountry();

    $scope.getCountryStates = function(){
        $scope.sates = CustomerService.getCountryState($scope.customer.Country);
        $scope.cities =[];
    };

    $scope.getStateCities = function(){
        $scope.cities = CustomerService.getStateCity($scope.customer.State);
    }
}]);

Since I am using dummy data in service so It is not very useful for you but just adding here in case it can help anyone to understand the concept

angular.module("myApp")
 .factory("CustomerService", ['$filter', 
  function($filter){

    var service = {};     

    var countrylist = [
        { "id": 1, "country": "USA" },
        { "id": 2, "country": "Canada" },
        { "id": 3, "country": "India" },
    ];

    var statelist = [
        {"Id":1, "state":"Alaska", "countryId": 1},
        {"Id":2, "state":"California", "countryId": 1},
        ........................
    ];

    var citylist = [
        {"Id":1, "city":"Anchorage", "stateId": 1},
        {"Id":2, "city":"Fairbanks", "stateId": 1},
        ........................
    ];

    service.getCountry = function(){    
        return countrylist;
    };

    service.getCountryState = function(countryId){
        var states = ($filter('filter')(statelist, {countryId: countryId}));
        return states;
    };


    service.getStateCity = function(stateId){
        var items = ($filter('filter')(citylist, {stateId: stateId}));      
        return items;
    };

    return service;       
}]);

Do you want to see the HTML, ok it is here:

<div ng-app="myApp"  class="container">
  <h3>Angularjs Cascading Dropdown/Select</h3>
  <form class="form-horizontal" ng-controller="dropdownCtrl">

    <div class="form-group">
      <label for="name" class="col-sm-2 control-label">
        Customer Name </label>
      <div class="col-sm-7"> 
        <input ng-model="customer.Name"  
               type="text"
               class="form-control" 
               ng-required="true"
               id="name" />
      </div>
    </div>

     <div class="form-group">
      <label for="country" class="col-sm-2 control-label">Country </label>
      <div class="col-sm-7">             
        <select ng-model="customer.Country"                
                ng-options="obj.id as obj.country for obj in countries"
                ng-change="getCountryStates()"
                class="form-control" 
                ng-required="true"
                id="country">
          <option value="">-- Choose Country --</option>
        </select>      
      </div>
    </div>

    <div class="form-group">
      <label for="state" class="col-sm-2 control-label">State </label>
      <div class="col-sm-7">       
        <select ng-model="customer.State" 
                ng-options="x.Id as x.state for x in sates"
                ng-change = "getStateCities()"
                class="form-control"
                ng-required="true"
                id="state">
          <option value="">-- Choose State --</option>
        </select>      
      </div>
    </div>

     <div class="form-group">
      <label for="city" class="col-sm-2 control-label">City </label>
      <div class="col-sm-7">       
        <select  ng-model="customer.City"
                ng-options="x.Id as x.city for x in cities"
                class="form-control" 
                ng-required="true"
                id="city">
          <option value="">-- Choose City --</option>
        </select>      
      </div>
    </div class="form-group">
      <div class="col-lg-offset-2">
          <button class="btn btn-success">  Save  </button>
      </div>
    <div class="form-group">
      <div class="col-lg-offset-2">
        <b>name:</b> {{customer.Name}}
        <b>Country:</b> {{customer.Country}}
        <b>State:</b> {{customer.State}}
        <b>City:</b> {{customer.City}} 
      </div>
    </div>  
  </form>
</div>

When I copied every thing then why not the CSS :)

input[type="text"].ng-invalid,
input[type="password"].ng-invalid,
input[type="date"].ng-invalid,
input[type="number"].ng-invalid,
select.ng-invalid{
    border-left: 5px solid #ff0000;
    background-color: #FFEBD6;
}

input[type="text"].ng-valid,
input[type="password"].ng-valid,
input[type="date"].ng-valid,
input[type="number"].ng-valid,
select.ng-valid{
    background-color: #FFFFFF;
    border-left: 5px solid #088b0b;
}

input[type="text"]:disabled.ng-valid{
    background-color: #efefef;
    border: 1px solid #ccc;
}
Ali Adravi Having 13+ years of experience in Microsoft Technologies (C#, ASP.Net, MVC and SQL Server). Worked with Metaoption LLC, for more than 9 years and still with the same company. Always ready to learn new technologies and tricks.
  • angularjs
  • select
  • dropdown
  • cascading
By Ali Adravi On 06 Aug, 15  Viewed: 33,854

Other blogs you may like

Angularjs powerful paging on table and searching with delay and demo

Paging on table is the basic requirement and most of us look for some grid so it can provide the complete feature of paging and sorting but in Angularjs it is so easy that anyone can achieve it by writing some code. I checked and found most of the available code give the paging feature in for 1 to... By Ali Adravi   On 14 Aug 2015  Viewed: 8,166

Angularjs CRUD with Web API, Entity Framework & Bootstrap modal popup part 2

Add/Edid Customer in Modal Popup --- In previous article we discussed how to search, delete and show detail of customer and contact list. In this article we will try to open the modal popup to add new customer and edit an existing customer record. I divided article in two parts because of the... By Ali Adravi   On 29 Jul 2015  Viewed: 13,153

Custom Directives in AngularJS with example and demo

Angularjs custom directives are the common to avoid the duplicate code, it is easy powerful and really nice. There are already too many directive have been created by experts but as a developer we need to write our own to achieve our specific goal. ng-model, ng-if, ng-show, ng-repeat all these are... By Ali Adravi   On 29 Jul 2015  Viewed: 2,496

Angularjs CRUD with Web API, Entity Framework & Bootstrap modal popup part 1

Search sort Insert update and delete are the basic features we need to learn first to learn any language, In this article we will try to create these features with Web API, bootstrap modal popup and ui.router. We will use enetity framework code first to save and retrieve data from database. We... By Ali Adravi   On 28 Jul 2015  Viewed: 23,540

Angularjs Progress bar directive for entire application

Progress bar for Angularjs application by using directives is simple and real easy. I was googling and could not found any directive way, if you will check most of the people says before call the http method open the progress bas and close once you get the result or get any error. Do you think it... By Ali Adravi   On 24 Jul 2015  Viewed: 10,610