Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Angular2 in ASP.NET MVC & Web API - Part 1

4.93/5 (162 votes)
11 Jul 2017CPOL28 min read 906.9K   26.2K  
This article will help beginners to step-up Angular2 in ASP.NET MVC, create the RESTful APIs in ASP.NET MVC Web API and front end in Angular2.
In this article, I will try to explain the step by step guide to create basic CRUD (create, read, update and delete) application using Angular2 and MVC Web API as backend RESTful APIs. I will create blank ASP.NET MVC application, setup the Angular2 environment and then create the web application that will have two pages, one for home page that will have only one image and the second will be User Management page where data will be loaded from SQL Server Database and user would have options to Add new user, Update and Delete existing user. For all database operation, Angular2 will call RESTful APIs that we will be developing using ASP.NET MVC Web API.

Articles in the Series

Introduction

This is a beginner level article and has been written for novice developers and students who have basic knowledge of programming and want to start learning Angular2, C# and RESTful APIs from scratch. If you are an experienced developer and only need an overview, you can just download the attached project and go through it. You need Visual Studio and SQL Server Management Studio to develop the project along with the article and compile the attached project.

Let's begin...

Setup Angular2 Environment

  1. Open Visual Studio. I am using Visual Studio 2017 Community, you can use Visual Studio 2015 Community with Update 3 installed for Node.js and TypeScript packages. (Read more about Visual Studio 2015 update 3.)
  2. Go to File menu and select File -> New -> Project:

    Image 1

  3. Enter the Project Name and select your desired .NET Framework (I am using .NET Framework 4.6 for this article). Click on OK button:

    Image 2

  4. Select MVC from the next screen and check Web API in Add folders and core reference options since we will create RESTful APIs for CRUD operations. Click on OK button:

    Image 3

  5. The basic ASP.NET MVC project is created. The next step is to prepare it for Angular2 application. Let's do it in the next steps.
  6. Right click on project Angular2MVC and select Add -> New Item:

    Image 4

  7. Enter package.json in top right search textbox, npm Configuration File would be filtered. Click on Add button to add package.json in project:

    Image 5

  8. We will use NPM (Node Package Manager) configuration file to manage all Angular2 packages. To read more about NPM, check this link.
  9. Next, copy the Package.json from Angular2 Quick Start GitHub link and paste it in newly added package.json file in Angular2MVC project:

    Image 6

  10. In dependencies section of package.json file, we can see all Angular2 related packages, check here to see the difference between ^ and ~ sign.
  11. Right click on package.json file and select option Restore Packages. Visual Studio Node.js tool will download all dependent packages mentioned in package.json file, in future if you need any additional package, just add it in DevDepnedencies section and restore it, it really makes life easier:

    Image 7

  12. You would find a new folder node_modules added in project that have all the downloaded packages:

    Image 8

  13. The next step to let our project know how to get these packages, we will add systemjs.config.js file. Right click on Angular2MVC project and select Add -> JavaScript file:

    Image 9

  14. Enter the name systemjs.config.js in Item name field and click on OK button:

    Image 10

  15. Copy the systemjs.config.js file's content from Angular2 Quick Start GitHub and paste it in newly added systemjs.config.js file in Angular2MVC project:

    Image 11

  16. Next let’s add the TypeScript JSON Configuration File by right clicking on Angular2MVC project and Add -> New Item. Select TypeScript JSON Configuration File and click on OK button:

    Image 12

  17. Copy the tsconfig.js file's content from Angular2 Quick Start GitHub and replace it with newly added tsconfig.js file in Angular2MVC project:

    Image 13

  18. In case you are getting a compilation error while trying to build, don’t worry. As soon we will start adding any typescript file, these errors will go away.
  19. Now that our Angular2 setup in ASP.NET MVC is almost completed, it’s time to develop the User Management application, but first we need database with one table where we will save the user information.

Create User Database & Entity Framework Model

SQL
CREATE TABLE [dbo].[TblUser] (
  [Id]     INT       IDENTITY (1, 1) NOT NULL,
  [FirstName] NVARCHAR (250) NULL,
  [LastName]  NVARCHAR (250) NULL,
  [Gender]   NVARCHAR (250) NULL,
  PRIMARY KEY CLUSTERED ([Id] ASC)
);

Image 14

  1. Right click on App_Data folder and select Add -> New item. In Data section, you can find the SQL Server Database option. Select it and specify the name as UserDB.

    Image 15

  2. Once database is created, double click on UserDB.mdf database file to open the Tables:

    Image 16

  3. Right click on UserDB.mdf and select New Query. Paste the following SQL query to create the TblUser table, click on Execute button to create the table:
  4. Right click on Tables folder and select option Refresh:

    Image 17

  5. Next let's develop the ASP.NET MVC side that includes setting up Layout and Index pages to load Angular2 main page along MVC controller to load index view and Web API 2.0 controllers for RESTful CRUD (Create, Read, Update and Delete) User APIs.
  6. Let’s first go to App_Start folder and configure the route to accept any URL since we can define our custom routing in Angular2 (will do it in upcoming steps). Double click on RouteConfig.cs file to edit it and change the URL in default route as follows:
    C#
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Routing;
    
    namespace Angular2MVC
    {
        public class RouteConfig
        {
            public static void RegisterRoutes(RouteCollection routes)
            {
                routes.IgnoreRoute("{resource}.axd/{*pathInfo}")
               routes.MapRoute(
                                name: "Default",
                                url: "{*anything}",
                                defaults: new { controller = "Home", 
                                action = "Index", id = UrlParameter.Optional }
                            );
            }
        }
    }

    Image 18

  7. Next let’s open our _Layout.cshtml, clean it up a little bit and add important JavaScripts files to run the Angular2 application. Open Views -> Shared -> _Layout.cshtml file. Remove the pre-added top menu and pages link. Add the following JS files and system.import statement in header section:
    HTML
    <script src="/node_modules/core-js/client/shim.min.js"></script>
    <script src="/node_modules/zone.js/dist/zone.js"></script>
    <script src="/node_modules/systemjs/dist/system.src.js"></script>
    <script src="/systemjs.config.js"></script>
    <script>
     System.import('app').catch(function(err){ console.error(err); });
    </script>
    
    Just a brief introduction about these JS files.

    Zone.js: A Zone is an execution context that persists across async tasks. For more information, click here.

    System.src.js & system.import(‘app’): Configurable module loader enabling dynamic ES module workflows in browsers and NodeJS. For more information, click here.

  8. Your final _Layout.cshtml should look like the following:

    Image 19

  9. Next let’s create the ADO.NET Entity Data Modal for UserDB database. Right click on Angular2MVC project and select Add -> New Folder, specify the name DBContext or anything you want to:

    Image 20

  10. Right click on newly created folder DBContext and select Add -> New Item:

    Image 21

  11. From left Panel under Visual C#, select Data. On the right side, select ADO.NET Entity Data Model. Enter the name UserDBEntities or any of your choice. Click on Add button.

    Image 22

  12. From the next screen, select EF Designer for Data, click on Next button:

    Image 23

  13. Click on New Connection button on the next screen:

    Image 24

  14. On the next screen, if Data Source is not selected as Microsoft SQL Server Database file (SqlClient), click on Change button and select it:Image 25

    Image 26

  15. In Database file name, click on Browse button: Image 27
  16. Browse to UserDB database created in earlier steps and saved in App_Data folder, click on OK button on both Select SQL Server Database File and Connection Properties windows:

    Image 28

    Image 29

  17. Check the Save Connection Settings in Web.Config as checkbox and click on Next button:

    Image 30

  18. In the next screen, you can select the Entity Framework version, I am using 6.x, you can use according to your choice:

    Image 31

  19. On the next screen, click on Tables checkbox, you would see the only one table TblUser, click on Finish button to end the wizard:

    Image 32

  20. It will take a few seconds and finally, you would see our database entity model having one table:

    Image 33

  21. Still at this point, if you would try to compile your project, you may get a lot of typescript errors, in order to solve it, create the folder with the name app, right click on it and select Add -> TypeScript File:

    Image 34

  22. Enter the name main.ts and click OK (we will use this file in the upcoming steps). Now rebuild the project, it should be successfully build.

Develop User Management RESTful APIs

  1. Next step is to create the ASP.NET MVC Web APIs for read, add, update and delete the user.
  2. First, we will create the Parent API controller that will have common methods that all API controllers would share, for now we will have only one method to serialize the class object into JSON string for Angular2 front end and also for UserDB database DBContext object to perform database operation in child controller. Right click on Controllers folder and select Add -> Controller…:

    Image 35

  3. Select the Web API 2 Controller – Empty and click on Add button:

    Image 36

  4. Enter the name BaseAPIController and click on Add button:

    Image 37

    Image 38

  5. Add the following code in BaseAPIController:
    C#
    protected readonly UserDBEntities UserDB = new UserDBEntities();
        protected HttpResponseMessage ToJson(dynamic obj)
        {
          var response = Request.CreateResponse(HttpStatusCode.OK);
          response.Content = new StringContent(JsonConvert.SerializeObject(obj), 
                             Encoding.UTF8, "application/json");
          return response;
        }
  6. The above given code is quite self-explanatory, we are creating UserDBEntities class object named as UserDB through which we can call methods to Load, Add, Update and Delete users. ToJson method is taking any kind of class object, creating the HTTP Response object with OK HttpStatusCode and serializing the object to JSON string by calling the JsonConvert method from Newtonsoft.json library. Final code should look like the following:

    Image 39

  7. Next, let’s create the RESTful Web APIs for User management, i.e., load all users from database, add new user, update and delete existing user. We are creating the following methods:
    1. GET method to read all users
    2. POST method to create new user
    3. PUT method to update the existing user
    4. DELETE method to delete existing user
  8. To read more about HTTP Verbs and methods, click here.
  9. Right click on Controllers folder and select Add -> Controller…

    Image 40

  10. Select Web API 2 Controller – Empty and click on Add button:

    Image 41

  11. Enter the name UserAPIController and click on Add button:

    Image 42

    Image 43

  12. Replace the UserAPIController class code with the following:
    C#
    public class UserAPIController : BaseAPIController
        {
            public HttpResponseMessage Get()
            {
                return ToJson(UserDB.TblUsers.AsEnumerable());
            }
    
           public HttpResponseMessage Post([FromBody]TblUser value)
            {
                UserDB.TblUsers.Add(value);             
                return ToJson(UserDB.SaveChanges());
            }
    
            public HttpResponseMessage Put(int id, [FromBody]TblUser value)
            {
                UserDB.Entry(value).State = EntityState.Modified;
                return ToJson(UserDB.SaveChanges());
            }
            public HttpResponseMessage Delete(int id)
            {
                UserDB.TblUsers.Remove(UserDB.TblUsers.FirstOrDefault(x => x.Id == id));
                return ToJson(UserDB.SaveChanges());
            }
        }
    1. UserAPIController is inherited from BaseAPIController to use UserDB object and ToJson method to convert User entity into JSON string and saving it in HTTP Response Message.
    2. Get(): Load all users from database and return the HTTP Response Message containing Users entity converted to JSON string.
    3. Post([FromBody]TblUser value): Take the User information from front end and save it to database. Return 1 for successfully saved.
    4. Put(int id, [FromBody]TblUser value): Take the existing user id and updated information and update it to database. Return 1 for successfully updated.
    5. Delete(int id): Take existing user id, load the user by id and delete it. Return 1 for successfully deleted.
  13. Final UserAPIController class should look like the following:

    Image 44

Develop Angular2 Application

  1. Now let’s start the exciting part of writing the Angular2 code. Before actually writing the code, it is very important to understand the Angular2 architecture, since I am not focusing on writing about Angular2 because you can find plenty of tutorials and free videos about it, let us revise the basic structure of Angular2 if you are lazy enough to go to angular.io website from here:
    1. Modules: Every Angular app has at least one Angular module class, the root module. The application is launched by bootstrapping its root module. During development, you're likely to bootstrap the AppModule in a main.ts file that we will create in next steps. Root module is conventionally named AppModule. In AppModule, we specify all components, services or custom pipe filters used by application.
    2. Components: Component controls the view on screen, you can define properties and methods to control the views. If you ever worked with ASP.NET forms, I would say components are like code behind files aspx.cs file where you interact the aspx file through methods and properties.
    3. Templates: You define a component's view with its companion template. A template is a form of HTML that tells Angular how to render the component. It is like an aspx file in ASP.NET form according to my previous step’s example.
    4. Metadata: Metadata tells Angular how to process a class. If you would see the component, it is just a class, MetaData tells what is template (code behind or you can HTML) associated with this component, any style sheet or how to use this component specified through Selector property.
    5. Data binding: In simple words, how information or control travels between template and component, e.g., when you would click any button in template, how would you get click event in component and perform your logic. Angular2 provides the following types of data bindings:
      1. {{}} interpolation displays any variable value declared in component.
      2. [ ] property binding is used to send value from parent component to child component. We will use it in our future chapters.
      3. ( ) event binding is used to get any event from template to component, e.g., (click).
    6. Directives: Two kinds of directives exist: structural and attribute directives.
      1. Structural directives alter layout by adding, removing, and replacing elements in DOM, e.g., *ngFor and *ngIf are used to loop through HTML element and show/hide the element.
      2. Attribute directives alter the appearance or behavior of an existing element. In templates, they look like regular HTML attributes, hence the name, e.g., ngStyle for style sheet, ngModel for two-way data binding.
    7. Services: Service is a broad category encompassing any value, function, or feature that your application needs. There is nothing specifically Angular2 about services. Angular2 has no definition of a service. There is no service base class, and no place to register a service. Services example are Error, Log, HTTP, etc. Component should only play the facilitator role between template and user. It should delegate rest of the functionality, e.g., fetching data from server, deleting or updating, logging, showing error, etc. to service.
    8. Dependency injection: Dependency injection is a way to supply a new instance of a class with the fully-formed dependencies it requires. Most dependencies are services. Angular2 uses dependency injection to provide new components with the services they need. E.g., for HTTP service, we will use dependency injection to provide the service instance to component in upcoming steps.
    9. For more details and for better understanding, please click here.
  2. Hopefully, you have got the basic idea about Angular2 architecture, let's create a user management page (Add, Update, Delete and View users) using Angular 2 in ASP.NET MVC using RESTFul APIs as backend services.
  3. In our project, we will create all Angular2 related code in app folder as the following convention, if you didn’t create app folder yet, go ahead and create one. If you followed the previous steps, you should have one typescript file main.ts in app folder that we will use to bootstrap the AppModule:

    Image 45

    Image 46Image 47

  4. Before moving further, let me show how our final application would look like. It will have two pages, one is home page with only large image and the second will have a table like view with user information, edit and delete button next to each record with one Add button on top of table to add new user. Each button will open modal pop up where you can perform corresponding functionality, following are the screen shots for both pages and each functionality:
  5. Now you have a basic idea about our final application. Let’s start developing the Angular2 piece of application. Let’s keep the Angular2 architecture in mind and create the basic architecture of application.
  6. First let's create the Angular2 Module that would be the entry point of application. Right click on app folder and select Add -> TypeScript File:
  7. If you don’t see the TypeScript File in second menu, right click on app folder, select Add -> New Item, search the TypeScript and select TypeScript file, enter the name and select OK button:
  8. Enter the name of new TypeScript File as app.module.ts and click on OK button:
  9. Add the following code in newly added app.module.ts:
    JavaScript
    import { NgModule } from '@angular/core';
    import { APP_BASE_HREF } from '@angular/common';
    import { BrowserModule } from '@angular/platform-browser';
    import { ReactiveFormsModule } from '@angular/forms';
    import { HttpModule } from '@angular/http';
     
     @NgModule({
        imports: [BrowserModule, ReactiveFormsModule, HttpModule],
        declarations: [],
        providers: [{ provide: APP_BASE_HREF, useValue: '/' }],
        bootstrap: []
    })
    
    export class AppModule { }
  10. Just to refresh your memory, we are using TypeScipt with Angular2. If you want to learn more about TypeScript, click here.
  11. If you quickly go through AppModule class, you can see that we are importing the required libraries, e.g., NgModule from Angular Core, similarly we will use Reactive forms for user, we are importing ReactiveFormModule from Angular Forms package. We will keep extending app.module.ts file by adding user components, service, modal pop up, etc.
    1. In NgModule meta data section:
      1. Imports contains modules list.
      2. Declarations contain list of components, we will add user components in next steps.
      3. Providers contains the list of services. We will add service with HTTP operations to perform user read, add, update and delete operations. Right now, it has base href path.
      4. Bootstrap contains the entry component, we will create app.component.ts file in the next steps and will add it here.
  12. The next step is to edit the main.ts in app folder and add the following code in it:
    JavaScript
    import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
    import { AppModule } from './app.module';
    platformBrowserDynamic().bootstrapModule(AppModule);

    Image 48

  13. main.ts code is quite self-explanatory. AppModule reference is imported from current folder, making it as entry Module and loading other helper resources (Bootstrapping) for application by using platformBrowserDynamic module’s bootstrapModule function. Bootstrap function initializes the Angular2 application, loads the required components, services or other helping resources to run the application. Try to build the project to avoid any error in next steps.
  14. Next, create two TypeScripts files, app.component.ts and app.routing.ts for main application component and routing table. We will come back to them later, right click on app folder and select Add -> TypeScript File:

    Image 49

  15. Enter the name app.component.ts and click on OK button:

    Image 50

  16. Again click on app folder and select Add -> TypeScript File, enter the name app.routing.ts and click on OK button:

    Image 51

    Image 52

  17. Next, let’s create the Home component with only one large picture:

    Image 53

  18. We will create all user components in new folder, right click on app folder and select Add -> New Folder, enter the name Components:

    Image 54

  19. Right click on newly created folder Component and select Add -> TypeScript File:

    Image 55

  20. Enter the name home.component.ts and click on OK button:

    Image 56

  21. Add the following code in newly created home.component.ts file:
    JavaScript
    import { Component } from "@angular/core";
    
    @Component({
    template: `<img src="../../images/users.png" style="text-align:center"/>`
    })
    
    export class HomeComponent{
    }

    Image 57

  22. In HomeComponent, you can see in MetaData’s template property, we have plain HTML image element from root images folder that will show users.png on screen. You can get any picture, save it in images folder and load it in HomeComponent.
  23. Right click on Angular2MVC project and select Add -> New Folder, enter the folder name as images:

    Image 58

  24. Right click on newly added folder images and select Open Folder in File Explorer, copy the given below image in opened location:

    Image 59

    Image 60

    Image 61

  25. Our HomeComponent is done, let's view it on screen. We need to do few more steps to do that. The first thing we will do is to create the Routing Table. If you worked with ASP.NET MVC, this routing table is the same as MVC Routing table. We will define custom routes for different view components. In the second step, we will create our main application component where we will create the navigation menu and load all view components.
    • Double click on app.routing.ts in app folder to edit it and add the following code:
    JavaScript
    import { ModuleWithProviders } from '@angular/core';
    import { Routes, RouterModule } from '@angular/router';
    import { HomeComponent } from './components/home.component';
    
    const appRoutes: Routes = [    
    { path: '', redirectTo: 'home', pathMatch: 'full' },
    { path: 'home', component: HomeComponent }
    ];
    
    export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes);

    Image 62

  26. In the above code, we are importing the routing libraries from angular router package and recently created HomeComponent from components folder. In app Routers, the path property is actual URL visible in browser address bar, e.g., http://localhost:4500/home. Once we will create the UserComponent, we will add another route for it.
  27. Next double click on app.component.ts in app folder to edit it and add the following code:
    JavaScript
    import { Component } from "@angular/core"
    @Component({
         selector: "user-app",
         template: `
                   <div>
                      <nav class='navbar navbar-inverse'>
                           <div class='container-fluid'>
                             <ul class='nav navbar-nav'>
                               <li><a [routerLink]="['home']">Home</a></li>
                          </ul>
                          </div>
                     </nav>    
                  <div class='container'>
                    <router-outlet></router-outlet>
                  </div>
                 </div>          
    `
    })
    
    export class AppComponent {
     
    }

    Image 63

  28. AppComponent is slim one having template with known bootstrap code to create navigation bar with one home link only. The routerlink home name for Home page is what we defined in app.routing.ts’s routing table. You can define whatever is convenient for you, e.g., default, index, etc. router-outlet acts as place holder for dynamically loaded view components. We also defined selector property (user-app) in AppComponent MetaData section because we will bootstrap AppComponent in AppModule and use this selector in MVC view (index.cshtml) to load it. For more information about router-outlet, click here.
  29. So we have created the Application Component (AppComponent), let’s go to AppModule and register HomeComponent and AppComponent along routing table. After that, we will add AppComponent to bootstrap, in order to do this all, update your app.module.ts according to the following:
    JavaScript
    import { NgModule } from '@angular/core';
    import { APP_BASE_HREF } from '@angular/common';
    import { BrowserModule } from '@angular/platform-browser';
    import { ReactiveFormsModule } from '@angular/forms';
    import { HttpModule } from '@angular/http';
    import { AppComponent } from './app.component';
    import { routing } from './app.routing';
    import { HomeComponent } from './components/home.component';
     
    @NgModule({
        imports: [BrowserModule, ReactiveFormsModule, HttpModule, routing],
        declarations: [AppComponent, HomeComponent],
        providers: [{ provide: APP_BASE_HREF, useValue: '/' }],
        bootstrap: [AppComponent]
    })
    
    export class AppModule { }

    Image 64

  30. You can see that we imported the HomeComponent and AppComponent, added it in declaration and bootstrapping the AppComponent as the entry point to our application. (Bootstrapping is more than just an entry point as discussed in the previous steps, you can search on Google to fully understand it. Here for simplicity, I am only referring it as the entry point).
  31. We are almost there to run our Angular2 application and view the Home page. Go to Views -> Home and double click on Index.cshtml to edit it:

    Image 65

  32. Delete the existing code and enter the following lines of code:
    Razor
    @{
        ViewBag.Title = "Index";
    }
    
    <body>
        <user-app>Loading…</user-app>
    </body>

    Image 66

  33. user-app is the selector for AppComponent, this is how we use the Component in HTML:

    Image 67

  34. Next in Solution Explorer, double click on systemjs.config.js and at the bottom, add main.js in packages section:

    Image 68

  35. Run the project, you should see the following web application with Home page and large image, you can see in address bar the page URL is ending with home that is the same URL we defined in routing table for Home page:

    Image 69

  36. So far, we have created basic architecture for Angular2 in ASP.NET MVC application with one static page. The next step is to create the User Management page that includes loading all users, adding new user, updating and deleting existing user:

    Image 70

  37. In User Management page, we will use TypeScript Interface (for User Model), Reactive forms and one third party component Ng2-Bs3-Modal for modal pop up.
    1. Interface: An interface is an abstract type, it does not contain any code as a class does. It only defines the signature or shape of an API that’s why we will use interface to define our User Model.
    2. Reactive Forms: Angular2 provides two kind of forms, Template driven and Reactive Forms (Model Driven Forms). There is a great article available for both forms here & here. if you are ASP.NET MVC developer, Reactive Forms is like MVC strongly typed Razor view.
  38. Next let's create the user interface. Right click on app folder and select Add -> New Folder. Enter the name of folder as Models:

    Image 71

    Image 72

  39. Right click on newly created Models folder and select Add -> TypeScript File, enter the file name as user.ts:

    Image 73

    Image 74

  40. Enter the following variables in newly created user interface:
    JavaScript
    export interface IUser {
        Id: number,
        FirstName: string,
        LastName: string,
        Gender: string
    }

    Image 75

  41. These interface properties are same as User table in database. The awesome thing about Angular2 is, user object will automatically be mapped to array of IUser interface when we will load data from database through RESTful API, in next steps, we will see how this is being done.
  42. Before moving to UserComponent, let's create some helping files, i.e., Global variables and Enumeration. I prefer to save all endpoints, error message and other shared variables in Global file and I am going to create Enumeration for CRUD operation. Right click on app folder and select Add ->New Folder, name the folder as shared:

    Image 76

    Image 77

  43. Right click on newly created shared folder and select Add -> TyepScript File, enter the name as global.ts:

    Image 78

  44. Copy the following code in global.ts:
    JavaScript
    export class Global {
        public static BASE_USER_ENDPOINT = 'api/userapi/';
    }

    Image 79

  45. This is simple exportable class with single static property BASE_USER_ENDPOINT having the base endpoint for user management RESTful APIs.
  46. Again, right click on shared folder and select Add -> TypeScript File, enter the name as enum.ts:

    Image 80

  47. Enter the following code in enum.ts file:
    JavaScript
    export enum DBOperation {
        create = 1,
        update = 2,
        delete =3
    }

    Image 81

  48. Enumeration is quite self-explanatory, instead of hard coded string for CRUD operations (“create”, “update”, ”delete”), we would use DBOperation enumeration.
  49. Next, let’s create the important functions to call ASP.NET RESTful Web API for user management using Angular2 HTTP service. As discussed in previous steps, we will create GET, POST, PUT and DELETE requests for RESTful users APIs that we already have created using ASP.NET MVC Web API in earlier steps. Right click on app folder and select Add -> New Folder, enter the name as Service.

    Image 82

  50. Right click on newly created Service folder and select Add -> TypeScript File, enter the name as user.service.ts:

    Image 83

    Image 84

    Image 85

  51. Copy the following code in user.service.ts file:
    JavaScript
    import { Injectable } from '@angular/core';
    import { Http, Response, Headers, RequestOptions} from '@angular/http';
    import { Observable } from 'rxjs/Observable';
    import 'rxjs/add/operator/map';
    import 'rxjs/add/operator/do';
    import 'rxjs/add/operator/catch';
    
    @Injectable()
    export class UserService {
      constructor(private _http: Http) { }
    
      get(url: string): Observable<any> {
        return this._http.get(url)
          .map((response: Response) => <any>response.json())
          // .do(data => console.log("All: " + JSON.stringify(data)))
          .catch(this.handleError);
      }
    
      post(url: string, model: any): Observable<any> {
        let body = JSON.stringify(model);
        let headers = new Headers({ 'Content-Type': 'application/json' });
        let options = new RequestOptions({ headers: headers });
        return this._http.post(url, body, options)
          .map((response: Response) => <any>response.json())
          .catch(this.handleError);
      }
    
      put(url: string, id: number, model: any): Observable<any> {
        let body = JSON.stringify(model);
        let headers = new Headers({ 'Content-Type': 'application/json' });
        let options = new RequestOptions({ headers: headers });
        return this._http.put(url+id, body, options)
          .map((response: Response) => <any>response.json())
          .catch(this.handleError);
      }
    
      delete(url: string, id: number): Observable<any> {
        let headers = new Headers({ 'Content-Type': 'application/json' });
        let options = new RequestOptions({ headers: headers });
        return this._http.delete(url+id,options)
          .map((response: Response) => <any>response.json())
          .catch(this.handleError);
      }
    
      private handleError(error: Response) {
        console.error(error);
        return Observable.throw(error.json().error || 'Server error');
      }
    }

    In order to understand the above code, we need to learn about Observable, you can easily get information about it just by searching it on Google but I would prefer to quickly go through the following link: https://scotch.io/tutorials/angular-2-http-requests-with-observables

  52. In just few lines, Observable is more like data stream, opposite to promise method (in Angular 1.x), Observable doesn’t return the response at once but in stream, it provides very helpful methods, e.g., map (for mapping result to interface), filter (filter any particular record from array of data) etc. Observable also provides HTTP request handling. Rxjs is an eternal library providing us all Observable methods.

  53. The first method is get, that is taking the RESTful API URL as a parameter and returning the Observable<any>, you can also specify the particular type of interface to return, e.g., Observable<IUser[]> but I try to keep it generic. In next lines, http get method is being called by providing the input RESTful API user, calling the map method to map the JSON response to any type, you can specify the particular type too like <IUser[]>response.json(). The type any is like a dynamic in C#, it does the compile type check.

    Image 86

  54. One awesome thing about RESTful API is the HTTP verbs like functions names, i.e., if function name is starting from GET, PUT, POST or DELETE, we only need base URL (endpoint), by the HTTP call, it automatically determines the corresponding function. It’s obvious, one Web API controller should have one HTTP verb method.
  55. The other methods POST, PUT and DELETE have almost same function body, creating the http header and sending the IUser interface in body where it is being received in Web API controller functions and automatically get converted to user entity because column name does match.
  56. Now that we created the user service, let’s add it to AppModule. Double click on app.module.ts file in app folder to edit it. Import the UserService by adding the following line:
    JavaScript
    import { UserService} from './Service/user.service'
  57. Add the UserService in AppModule providers section.

    Image 87

  58. After this, let's create the UserComponent. Right click on Components folder and select Add -> TypeScript File:

    Image 88

  59. Enter the name as user.component.ts:

    Image 89

  60. We will create the template in separate html file so right click on Components folder again select Add-> HTML Page:

    Image 90

  61. Enter the name as user.component.html:

    Image 91

  62. Before going to UserComponent, let's configure one third party component for modal pop ng2-bs3-modal. It’s very simple to use.
  63. Double click on Package.json file in Angular2MVC project and add the following package in devDependencies section:
    "ng2-bs3-modal": "0.10.4"

    Image 92

  64. Now let’s download this package from NPM, right click on package.json and select Restore Packages:

    Image 93

  65. Double click on systemjs.config.js in Angular2MVC project:
  66. Add the following text in map section:
    'ng2-bs3-modal': 'npm:/ng2-bs3-modal'
  67. Add the following text in packages section:

    JavaScript
    'ng2-bs3-modal':
    { main: '/bundles/ng2-bs3-modal.js', defaultExtension: 'js' }
    
  68. Final update should look like the following:

    Image 94

  69. Now since we got our modal pop up, let’s create the UserComponent that will have view all users, add new user, edit and delete existing users. Double click on user.component.ts file in app -> components folder to edit:

    Image 95

  70. First add the following import statements:
    JavaScript
    import { Component, OnInit, ViewChild } from '@angular/core';
    import { UserService } from '../Service/user.service';
    import { FormBuilder, FormGroup, Validators } from '@angular/forms';
    import { ModalComponent } from 'ng2-bs3-modal/ng2-bs3-modal';
    import { IUser } from '../Models/user';
    import { DBOperation } from '../Shared/enum';
    import { Observable } from 'rxjs/Rx';
    import { Global } from '../Shared/global';
  71. We are importing Components, OnInit (to use OnInit event), ViewChild (to access Modal pop up properties).
  72. Then we are importing the UserService that executes the HTTP calls to server.
  73. In UserComponent, we are going to use Reactive (Model-driven) forms that I found way more organized and easy to use than template driven forms. To me, it looks like a strongly type ASP.NET MVC razor view, it is also good for unit testing. The form fields, validations and validation errors can be managed on TypeScript side and HTML view has minimum form logic that is good practice to keep the code at one place. To read more about Reactive form, click here.
  74. ModalComponent is third party modal pop up that we downloaded in previous steps.
  75. IUser is the interface we will use as a Model, to store the user information.
  76. DBOperation and Global are enumeration and global variables.
  77. Observable, we briefly discussed in previous steps. We will use subscribe and filter function from Rxjs library.
  78. Next copy the following Component meta data information under the import statements:
    JavaScript
    @Component({
        
    templateUrl: 'app/Components/user.component.html'
    
    })
  79. Since User is a parent component and we will not use it in any other component, we are not specifying the Selector property. HTML for User component would be in user.component.html file.
  80. Next let’s start the UserComponent class body and declare the required variable:
    JavaScript
    export class UserComponent implements OnInit 
    {
        @ViewChild('modal') modal: ModalComponent;
        users: IUser[];
        user: IUser;
        msg: string;
        indLoading: boolean = false;
        userFrm: FormGroup;
        dbops: DBOperation;
        modalTitle: string;
        modalBtnTitle: string;
    }
  81. We are starting our class with export and then with our UserComponent name, since we will use onInit event, our class must implement this.
  82. The next line is starting with @ViewChild(‘modal’), the modal is placeholder for Modal pop up component that we will create in HTML template. This is the syntax if you want to access any HTML element in TypeScript. :ModalComponent specify the type of element.
  83. Next we are creating the array of IUser interface to hold the list of users and single User to hold one user information for add, edit and delete. Others are few string and Boolean variables that we will use in next steps to show some messages.
  84. As we discussed in previous steps, we will use Reactive (Model-driven) form, so we create the userform of Formgroup type.
  85. Next is to add the constructor for UserComponent class:
    JavaScript
    constructor(private fb: FormBuilder, private _userService: UserService) { }
  86. On great thing about Angular2 is dependency injection, in constructor you can see, we are getting the FormBuilder and UserService instances though DI. To read more about DI, click here.
  87. So far, our UserComponent should look like the following:

    Image 96

  88. At this point, you might be getting an error because still ngOnInit event is not implemented, let’s go ahead and add ngOnInit event, we will create and initialize our Reactive User form:
    JavaScript
    ngOnInit(): void {
    
            this.userFrm = this.fb.group({
                Id: [''],
                FirstName: ['', Validators.required],
                LastName: [''],
                Gender: ['']
            });
            
           this.LoadUsers();
        
         }
  89. We are initializing the User form, specifying the form elements and validation rules. Right now, form is initialized with empty string ‘’.
  90. Next let's create the LoadUsers method, as name says, this method will call the get method from UserService to load all users from database through RESTful API:
    JavaScript
    LoadUsers(): void {
               this.indLoading = true;
               this._userService.get(Global.BASE_USER_ENDPOINT)
                .subscribe(users => { this.users = users; this.indLoading = false; },
                error => this.msg = <any>error);
    
               }
  91. Subscribe is the part of Observable that we discussed in previous steps. Once the user loads would be complete, it will save it in users variable. In case of any error, error message would be saved in msg variable. indLoading is the Boolean variable we are using here to show loading message until full response would be loaded.

  92. Next, let’s add three methods to show modal pop up for Add, Update and Delete user. Add the following code for these functions:

    JavaScript
    addUser() {
           this.dbops = DBOperation.create;
           this.SetControlsState(true);
           this.modalTitle = "Add New User";
           this.modalBtnTitle = "Add";
           this.userFrm.reset();
           this.modal.open();
       }
    
       editUser(id: number) {
           this.dbops = DBOperation.update;
           this.SetControlsState(true);
           this.modalTitle = "Edit User";
           this.modalBtnTitle = "Update";
           this.user = this.users.filter(x => x.Id == id)[0];
           this.userFrm.setValue(this.user);
           this.modal.open();
       }
    
       deleteUser(id: number) {
           this.dbops = DBOperation.delete;
           this.SetControlsState(false);
           this.modalTitle = "Confirm to Delete?";
           this.modalBtnTitle = "Delete";
           this.user = this.users.filter(x => x.Id == id)[0];
           this.userFrm.setValue(this.user);
           this.modal.open();
       }
  93. All these methods are resembling so let’s take AddUser method and understand it. First, we are storing current DB operation in dpops variable that is of DBOperation enumeration type. Next, we are calling SetControlsState method that will enable or disable form controls. Next variables are setting the modal pop up heading and button title. In only AddUser function, we are resetting form to clearing the form. Next, we are calling modal.open() function to view the modal pop up. In edit and delete user method, we are getting UserID as parameter, calling the Observable’s filter method to get single user from users list. The filter syntax is like anonymous method in C#. The next line is to assign the single user to user form that will set the value to the front end, piece of cake.

  94. Let’s create the SetControlsState that will enable or disable the form. Reactive form has enable and disable methods that make the control read-only and editable.

    JavaScript
    SetControlsState(isEnable: boolean)
    {
     isEnable ? this.userFrm.enable() : this.userFrm.disable();
    }
  95. The next method is onSubmit that actually get the form values and based on DBOperation enumeration value, it performs add, update and delete operation, we are using simple switch statement, paste the following code:

    JavaScript
    onSubmit(formData: any) {
        this.msg = "";
      
        switch (this.dbops) {
          case DBOperation.create:
            this._userService.post(Global.BASE_USER_ENDPOINT, formData._value).subscribe(
              data => {
                if (data == 1) //Success
                {
                  this.msg = "Data successfully added.";
                  this.LoadUsers();
                }
                else
                {
                  this.msg = "There is some issue in saving records, 
                              please contact to system administrator!"
                }
                 
                this.modal.dismiss();
              },
              error => {
               this.msg = error;
              }
            );
            break;
          case DBOperation.update:
            this._userService.put(Global.BASE_USER_ENDPOINT, 
                                  formData._value.Id, formData._value).subscribe(
              data => {
                if (data == 1) //Success
                {
                  this.msg = "Data successfully updated.";
                  this.LoadUsers();
                }
                else {
                  this.msg = "There is some issue in saving records, 
                              please contact to system administrator!"
                }
    
                this.modal.dismiss();
              },
              error => {
                this.msg = error;
              }
            );
            break;
          case DBOperation.delete:
            this._userService.delete(Global.BASE_USER_ENDPOINT, 
                                     formData._value.Id).subscribe(
              data => {
                if (data == 1) //Success
                {
                  this.msg = "Data successfully deleted.";
                  this.LoadUsers();
                }
                else {
                  this.msg = "There is some issue in saving records, 
                              please contact to system administrator!"
                }
    
                this.modal.dismiss();
              },
              error => {
                this.msg = error;
              }
            );
            break;
        }
      }
  96. The code is quite simple and self-explanatory, once we submit the form, it sends all the values that we can get through .value property. That’s pretty much it on the TypeScript side.

  97. Let’s write the HTML template for UserComponent. Double click on user.component.html to edit it:

    Image 97

  98. Copy the following code in user.component.html:

    HTML
    <div class='panel panel-primary'>
      <div class='panel-heading'>
        User Management
      </div>
      <div class='panel-body'>
        <div class='table-responsive'>
          <div style="padding-bottom:10px"><button class="btn btn-primary" 
          (click)="addUser()">Add</button></div>
          <div class="alert alert-info" role="alert" 
          *ngIf="indLoading"><img src="../../images/loading.gif" 
          width="32" height="32" /> Loading...</div>
          <div *ngIf='users && users.length==0' 
          class="alert alert-info" role="alert">No record found!</div>
          <table class='table table-striped' *ngIf='users && users.length'>
            <thead>
              <tr>
                <th>First Name</th>
                <th>Last Name</th>
                <th>Gender</th>
                <th></th>
              </tr>
            </thead>
            <tbody>
              <tr *ngFor="let user of users">
                <td>{{user.FirstName}}</td>
                <td>{{user.LastName}}</td>
                <td>{{user.Gender}}</td>
                <td>
                  <button title="Edit" class="btn btn-primary" 
                  (click)="editUser(user.Id)">Edit</button>
                  <button title="Delete" class="btn btn-danger" 
                  (click)="deleteUser(user.Id)">Delete</button>
                </td>
              </tr>
            </tbody>
          </table>
          <div>
          </div>
        </div>
        <div *ngIf="msg" role="alert" 
        class="alert alert-info alert-dismissible">
          <button type="button" class="close" 
          data-dismiss="alert" aria-label="Close">
          <span aria-hidden="true">&times;</span></button>
          <span class="glyphicon glyphicon-exclamation-sign" 
          aria-hidden="true"></span>
          <span class="sr-only">Error:</span>
          {{msg}}
        </div>
      </div>
    </div>
    
    <modal #modal>
      <form novalidate (ngSubmit)="onSubmit(userFrm)" [formGroup]="userFrm">
        <modal-header [show-close]="true">
          <h4 class="modal-title">{{modalTitle}}</h4>
        </modal-header>
        <modal-body>
    
          <div class="form-group">
            <div>
              <span>Full name*</span>
              <input type="text" class="form-control" 
              placeholder="First Name" formControlName="FirstName">
            </div>
            <div>
              <span>Full name</span>
              <input type="text" class="form-control" 
              placeholder="Last Name" formControlName="LastName">
            </div>
            <div>
              <span>Gender*</span>
              <select formControlName="Gender" class="form-control">
                <option>Male</option>
                <option>Female</option>
              </select>
            </div>
          </div>
        </modal-body>
        <modal-footer>
          <div>
            <a class="btn btn-default" (click)="modal.dismiss()">Cancel</a>
            <button type="submit" [disabled]="userFrm.invalid" 
            class="btn btn-primary">{{modalBtnTitle}}</button>
          </div>
        </modal-footer>
      </form>
    </modal>
  99. If you look at the Add button, we are calling the AddUser function by using (click) function that is the example of event binding we discussed in previous steps.

  100. Next, we are using *ngIf, the structural directives to show the loading message based on indLoading Boolean variable.

  101. Next, we are using *ngFor structural directive to loop through the users array and showing the user information.

  102. Next code is for modal pop up, you can see #modal placeholder that we are using to access it on TypeScript side through @ViewChild to access open and dismiss functions.

  103. Next we are creating the form, (ngSumbit) event will send the form data to TypeScript onSumit function.

  104. Through [formgorup] property binding, we are assigning the userform that we created on TypeScript side. We are telling our template the corresponding form control through formControlName property.

  105. Add and Edit buttons will be disabled until form gets valid. This is being handled by [disabled] property binding until userform.invalid property get enabled.

  106. That’s it with UserComponent, now let’s add the routing for UserComponent and add to it AppModule.

  107. Double click on app.routing.ts in app folder to edit it:

    Image 98

  108. Import the UserComponent by the following code:

    JavaScript
    import { UserComponent } from './components/user.component';
  109. Add the UserComponent route as follows:

    JavaScript
    { path: 'user', component: UserComponent }

    The final app.routing.ts should look like the following:

    Image 99

  110. Edit the app.component.ts by double clicking on it:

    Image 100

  111. Add User Component in App Module:

    JavaScript
    import { UserComponent } from './components/user.component';
  112. Add the UserComponent in declaration section, the final AppModule should look like the following:

    Image 101

  113. Add menu item for User Management, double click on app.component.ts and add the following line:

    HTML
    <li><a [routerLink]="['user']">Users Management</a></li>
  114. Final app.component.ts should be as follows:

    Image 102

  115. Compile and run the application.

History

  • 16th April, 2017: Created
  • 21st May, 2017: Added Part 2
  • 12th August, 2017: Attached Angular 4 Solution

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)