In this post, we take it to next level and implement it with ASP.NET Core Web API and AngularJS 2. But starting/configuring AngularJS 2 with ASP.NET Core is not straight forward and it requires some manual configurations to be done. If you are not sure how to do it, I recommend you to read this helpful post to find out post how to start with AngularJS 2 in ASP.NET Core with TypeScript using Visual Studio 2015.

Cascading DropDown List with ASP.NET Core WEB API and AngularJS 2

I believe now you have an idea about starting with AngularJS 2. I also followed same steps to configure this demo project as mentioned. So now let’s move to next part. Please note, I selected the “Web application template” while creating the project but removed all the unnecessary code.

Add Models classes in Models folder

First, add Country and State model classes in Models folder. Following is the code for Country.cs. This class has 2 properties and a method which returns a list of countries. For demo, I used static data but you can also get the same list from database.

public class Country
{
    public int id { get; set; }
    public string name { get; set; }

    public Country(int CountryID, string CountryName)
    {
        id = CountryID;
        name = CountryName;
    }

    public static List<Country> GetAllCountries()
    {
        List<Country> lstCountries = new List<Country>();
        lstCountries.Add(new Country(1, "USA"));
        lstCountries.Add(new Country(2, "India"));
        lstCountries.Add(new Country(3, "Australia"));
        lstCountries.Add(new Country(4, "Canada"));
        return lstCountries ;
    }
}

And following is the code for State.cs. This class has 3 properties and a method which returns a list of states. Nothing fancy, self-explanatory code.

public class State
{
    public int id { get; set; }
    public int countryid { get; set; }
    public string name { get; set; }

    public State(int StateID, int CountryID, string StateName)
    {
        id = StateID;
        countryid = CountryID;
        name = StateName;
    }
    public static List<State> GetAllStates()
    {
        List<State>  lstState = new List<State>();
        lstState.Add(new State(1, 1, "Arizona"));
        lstState.Add(new State(2, 1, "Alaska"));
        lstState.Add(new State(3, 1, "Florida"));
        lstState.Add(new State(4, 1, "Hawaii"));
        lstState.Add(new State(5, 2, "Gujarat"));
        lstState.Add(new State(6, 2, "Goa"));
        lstState.Add(new State(7, 2, "Punjab"));
        lstState.Add(new State(8, 3, "Queensland"));
        lstState.Add(new State(9, 3, "South Australia"));
        lstState.Add(new State(10, 3, "Tasmania"));
        lstState.Add(new State(11, 4, "Alberta"));
        lstState.Add(new State(12, 4, "Ontario"));
        lstState.Add(new State(13, 4, "Quebec"));
        lstState.Add(new State(14, 4, "Saskatchewan"));
        return lstState;
    }
}


Add action methods in controller
Next step is to make our WEB API ready. For your information, ASP.NET Core comes with Unified Programming Model for MVC and Web API. So open HomeController.cs and add following 2 action methods.

[HttpGet]
[Route("api/Home/GetCountries")]
public IEnumerable<Country> GetCountries()
{
    return Country.GetAllCountries();
}

[HttpGet]
[Route("api/Home/GetState/{countryid?}")]
public IEnumerable<State> GetState(int countryid = 1)
{
    List<State> lstState = State.GetAllStates();
    return lstState.Where(item => item.countryid == countryid);
}
GetCountries() method makes call to Country.GetAllCountries(); and returns the list. Where the second method GetState() accepts countryid as parameters and based on the its value, filters the state list and return the same.

Note countryid parameter is optional for GetState() action method. And also a default value is supplied to it. Why? Well, this actually allows you to pass countryid in querystring. And while calling REST APIs via AngularJS, the arguments/parameters are appended to URL as part of querystring. And that’s why we must allow our API to support querystring. So following URL,

http://localhost:53483/api/Home/GetState/1
is similar to
http://localhost:53483/api/Home/GetState?countryid=1

AngularJS 2 application structure
Create a folder named “app” in wwwroot folder. If you have already created while configuring AngularJS 2 then ignore this step. Now within this folder, following files needs to added.

I already explained about this application structure and about code here. But let me just summarize here again.

country.ts: This file has a simple class called Country with 2 properties id and name.
state.ts: This file has a simple class called States with 3 properties id, countryid and name.
countrylistcomponent.ts: This file contains code for defining a component and template used to render HTML. The Component adds the metadata to the class. And it also makes call to Angular 2 Service, which in turn calls WEB API.
CountryTemplate.html: This file has HTML code to render select dropdown list.
dataservice.ts: This is an Angular 2 service which makes WEB API calls to get list of countries and states.
main.ts: This file contains code to bootstrap angularjs 2 in our application.
country.cs

export class Country {
    constructor(public id: number, public name: string) { }
}
state.cs

export class State {
    constructor(public id: number,
                public countryid: number,
                public name: string) { }
}
dataservice.ts

import { Injectable } from 'angular2/core';
import {Http, URLSearchParams} from "angular2/http";
import 'rxjs/Rx';
import { Country } from './country';
import { State } from './state';


@Injectable()
export class DataService {
    constructor(public http: Http) {
        this.http = http;
    }
    getCountries() {
        return this.http.get("/api/Home/GetCountries")
            .map((responseData) => responseData.json());
    }

    getStates(countryid: string) {
        var params = new URLSearchParams();
        params.set('countryid', countryid);
        return this.http.get("/api/Home/GetState", { search: params })
            .map((responseData) => responseData.json());
    }
}

As you know AngularJS 2 is modular. And as here in this service, we need to make use of HTTP service. So we need to import it. Similarly URLSearchParams, which is used to pass arguments to WEB API method. Therefore,
import {Http, URLSearchParams} from "angular2/http";

And the other import statement import 'rxjs/Rx';, imports ReactiveX library. The Http service in Angular 1 returns a promise where Angular 2 returns an Observable object. And The Observable classes in Angular 2 are provided by the ReactiveX library.

Here, first we inject $http service in class constructor. And we use http.get() to run our HTTP request. And this returns an Observable object. Since it’s an observable object, we can use map() to convert the response into JSON response.

countrylistcomponent.ts

import { Component } from 'angular2/core';
import { DataService } from './dataservice';
import { Country } from './country';
import { State } from './state';

@Component({
    selector: 'my-country-list',
    templateUrl: 'app/CountryTemplate.html',
    providers: [DataService]
})
export class CountryListComponent {
    selectedCountry: Country = new Country(0, 'India');
    countries: Country[];
    states: State[];

    constructor(private _dataService: DataService) {
        this._dataService.getCountries().subscribe(data => { this.countries = data });
    }

    onSelect(countryid) {
        if (countryid == 0)
            this.states = null;
        else
            this._dataService.getStates(countryid).subscribe(data => { this.states = data });
    }
}
This file is modified to use the service to get countries and states list.

First, import the Service and then within @Component directive, set providers: [DataService].
And inject the service in CountryListComponent constructor. And in constructor, call getCountries() method to get list of countries from the service. Since the service returns Observable object, we can use .subscribe() method to get the output in variable.
Also defined onSelect method which will be called onChange event of country dropdown list. This method calls service to get the list of states based on selected countryid and then using subscribe get the list in states variable.
main.ts

import { bootstrap } from 'angular2/platform/browser';
import {HTTP_PROVIDERS} from "angular2/http";
import { CountryListComponent } from './countrylistcomponent';

bootstrap(CountryListComponent, [HTTP_PROVIDERS]);
This file has code to bootstrap AngularJS 2 in our application. Along with that, it also bootstrap application root/parent component. Angular’s http module exposes HTTP_PROVIDERS, which has all the providers that we need, to code http action in our service. Therefore add the http providers to the bootstrap, by importing the HTTP_PROVIDERS from angular2/http.

CountryTemplate.html

<div class="row">
    <div class="col-md-5" style="text-align:right;">
        <label>Country:</label>
    </div>
    <div class="col-md-7" style="text-align:left;">
        <select [(ngModel)]="selectedCountry.id" (change)="onSelect($event.target.value)" style="width:150px;">
            <option value="0">--Select--</option>
            <option *ngFor="let country of countries" value={{country.id}}>{{country.name}}</option>
        </select>
    </div>
</div>
<br />
<div class="row">
    <div class="col-md-5" style="text-align:right;">
        <label>State:</label>
    </div>
    <div class="col-md-7" style="text-align:left;">
        <select style="width:150px;">
            <option value="0">--Select--</option>
            <option *ngFor="let state of states " value={{state.id}}>{{state.name}}</option>
        </select>
    </div>
</div>
And finally the HTML template. This file name is used while specifying metadata for CountryListComponent class.
There are 2 dropdowns list one for country and other for state and also change event defined on country dropdown list. Angular 2 has different way of defining event. Take the HTML event and wrap it with parentheses. $event.target.value will give the selected country id.

I also want to bring in your attention a change made in AngularJS 2 version “2.0.0-beta.17” with respect to *ngFor. Previously we were using,

*ngFor="#state of states"
but in this version, it is changed a bit. Instead of “#”, use “let”

*ngFor="let state of states"
And finally since we are using Angular 2 Http service in our application, we need to include the script in the layout. So, open the _Layout.cshtml file located at Views/Shared/ and add the following code right after the script element that loads Angular 2 core.

<environment names="Development">
  <script src="~/lib/npmlibs/angular2/http.dev.js"></script>
</environment>
<environment names="Staging,Production">
  <script src="~/lib/npmlibs/angular2/http.min.js"></script>
</environment>
Wait!!! We still need to show what we have done till now on UI. So open Views/Home/Index.cshtml and add angular component tag <my-country-list></my-country-list> to HTML file. And we also need to load the application and all its modules. So place following script section to the end of the file.

@section Scripts {
    <script>
        System.config({
            packages: {
                'app': { defaultExtension: 'js' },
                'lib': { defaultExtension: 'js' },
            },
        });

        System.import('app/main')
            .then(null, console.error.bind(console));
    </script>
}

 

 

HostForLIFE.eu ASP.NET Core 1.0 Hosting
European best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.