Mozart Al Khateeb

Full Stack

Mobile

.Net Developer

ERP Developer

Mozart Al Khateeb

Full Stack

Mobile

.Net Developer

ERP Developer

Blog Post

To Do Rest API Using Asp.net Core – Angular Client (Part 4)

June 26, 2019 Front End, Web Development
To Do Rest API Using Asp.net Core – Angular Client (Part 4)

This post is a continuation for previous posts, to follow along you have to at least complete part 1 and part 2 where we built a restful web service using Asp.net Core or you can grab the source code from GitHub.

In this post we are going to create an angular client for our Web API. Angular is pretty popular out there and you can find endless tutorials but in this tutorial i’m going to keep things as simple as possible so beginners could find an easy tutorial to start with.

Tools

Getting Started

Installing angular

Open your command prompt as administrator and install angular using the following command.

npm install -g @angular/cli

The above command install the latest version of angular globally (angular 8 now). Then navigate to your work space and create a new app using the following command.

ng new ToDo-Angular

We are not going to use routing in this tutorial so choose no for routing and css for style sheets. Now that everything is ready you can build and run your app using the following command.

ng serve -o

The ng new command provided us with a starter template that we can use to build upon.

Calling The Web API From Angular

First you need to launch you Todo Rest API, to keep things simple I will put all the type script code inside app.component.ts but in production apps you should organize your code into different sections see. To be able to create http requests we need to import HttpClientModule into our app.modules .

app.modules
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    // import HttpClientModule after BrowserModule.
    HttpClientModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
Get Request

To make a get request we need to import Http Client that we referenced in app.modules. Then we inject HttpClient into our constructor, this code makes a get request to our web API and logs the response to the console.

app.component.ts
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'ToDo-Angular';
  baseUrl = 'http://localhost:58635/api';

  constructor(private http: HttpClient) {
    http.get(this.baseUrl + "/ToDos").subscribe((response) => {
      console.log(response);
    });
  }
}

To open the console Press Right Click and Select inspect element or use Ctrl + Shift + I. Go to the console tab, if you do not see any output refresh the page and you should see a Json array with all the Todo Items.

Displaying Todos inside our Web Page

I will try to make the closest styling possible to that we used in the blazor example, so we will need to add a reference to Bootstrap 4 and Open Iconic, to do that add the following lines to the index.html file as below, below the meta tag.

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/open-iconic/1.1.1/font/css/open-iconic-bootstrap.min.css" integrity="sha256-BJ/G+e+y7bQdrYkS2RBTyNfBHpA9IuGaPmf9htub5MQ=" crossorigin="anonymous" />

In order to access our API Response we need to create a variable in app.component.ts that hold our Json data. so modify your code as below.

  todos: any

  constructor(private http: HttpClient) {
    http.get(this.baseUrl + "/ToDos").subscribe((response) => {
      this.todos = response;
      console.log(response);
    });
  }

Next we need to modify our HTML template to show our DTO list. So replace the app.component.html content with the following.

<!--The content below is only a placeholder and can be replaced.-->
<div style="text-align:center">
  <h1>
    Welcome to {{ title }}!
  </h1>
</div>
<div class="container">
  <div class="row">
    <div class="col-12">
      <div class="card">
        <h2>ToDos</h2>
        <div class="card-body">
          <ul class="list-group">
            <div *ngFor="let todo of todos; index as i;">
              <div [ngSwitch]="todo.status">
                <li *ngSwitchCase="'Pending'"
                  class="list-group-item list-group-item-info d-flex justify-content-between align-items-center">
                  <span>{{todo.description}}</span>
                  <div>
                    <span class="font-weight-bold">{{todo.status}}</span>
                  </div>
                </li>
                <li *ngSwitchCase="'In Progress'"
                  class="list-group-item list-group-item-success d-flex justify-content-between align-items-center">
                  <span>{{todo.description}}</span>
                  <div>
                    <span class="font-weight-bold">{{todo.status}}</span>
                  </div>
                </li>
                <li *ngSwitchCase="'Done'"
                  class="list-group-item list-group-item-primary d-flex justify-content-between align-items-center">
                  <span>{{todo.description}}</span>
                  <div>
                    <span class="font-weight-bold">{{todo.status}}</span>
                  </div>
                </li>
                <li *ngSwitchCase="'Cancelled'"
                  class="list-group-item list-group-item-warning d-flex justify-content-between align-items-center">
                  <span>{{todo.description}}</span>
                  <div>
                    <span class="font-weight-bold">{{todo.status}}</span>
                  </div>
                </li>
              </div>
            </div>
          </ul>
        </div>
      </div>
    </div>
  </div>
</div>

Now you should see Todo list similar to what we did in the blazor project. The code is not complex, as you can see we are creating a for loop using ngFor with a nested switch statement to apply different style based on the status of the Todo item.

Adding a new Todo Item

In order to create a post request we need a form, for this we have to add an import inside our app.modules for FormsModule .

app.module.ts
.
.
import { HttpClientModule } from '@angular/common/http';
import { FormsModule }   from '@angular/forms';
.
.
HttpClientModule,
FormsModule

Next we will create an empty object to bind to our form. Add it below todos: any.

app.component.ts
  todos: any
  todoModel: any = {}

Note: Usually we create TypeScript interfaces and classes instead of dummy JS objects, doing that gives us with IntelliSense, clean code and clear structure. but for this little example it would be boring to create a handful of files.

Back to our html we will create a little form and bind it to our todoModel Object. So below the div with container class add the following code.

  <form #form="ngForm" (ngSubmit)="onSubmit()">
    <div class="row">
      <div class="col-8">
        <input placeholder="Something todo" [(ngModel)]="todoModel.description" name="description"
          class="form-control" />
      </div>
      <div class="col-2">
        <select [(ngModel)]="todoModel.status" name="status">
          <option value="Pending">Pending</option>
          <option value="In Progress">In Progress</option>
          <option value="Done">Done</option>
          <option value="Cancelled">Cancelled</option>
        </select>
      </div>
      <div class="col-2">
        <button type="submit" class="btn btn-primary  mb-2">Save Todo</button>
      </div>
    </div>
  </form>
Submit method

Below is the submit method, I have applied some refactoring to the code to make use of the get method.

import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'ToDo-Angular';
  baseUrl = 'http://localhost:58635/api';
  todos: any
  todoModel: any = {}

  constructor(private http: HttpClient) {
    this.getDtos()
  }

  onSubmit() {
    this.http.post(this.baseUrl + "/ToDos", this.todoModel).subscribe((response) => {
      console.log(response);
      this.todoModel= {} //Empty our object
      this.getDtos() //Get updated dto list
    });
  }

  getDtos(){
    this.http.get(this.baseUrl + "/ToDos").subscribe((response) => {
      this.todos = response;
      console.log(response);
    });
  }
}
Updating a Todo Item

To update a Todo item we need to populate our form with its values and since the form is bound to the todoModel, populating this object is enough to achieve what we want. So we will add an edit button that will take the current list item and push it to the todoModel. Add the following line of code under: <span class=”font-weight-bold”>{{todo.status}}</span> inside each of the switch statements.

<span class="ml-5"><button class="btn btn-outline-primary oi oi-pencil" (click)="onEdit(todo)"></button></span>

Next we will add the edit method that take the selected Todo item as a parameter. Then inside the onSubmit method we will check if the object has an id then we make an update, else we make an add.

app.component.ts Full code
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'ToDo-Angular';
  baseUrl = 'http://localhost:58635/api';
  todos: any
  todoModel: any = {}

  constructor(private http: HttpClient) {
    this.getDtos()
  }

  onSubmit() {
    if(this.todoModel.id){
      this.http.put(this.baseUrl + "/ToDos/" + this.todoModel.id, this.todoModel).subscribe((response) => {
        console.log(response);
        this.todoModel= {} //Empty our object
        this.getDtos() //Get updated dto list
      });
    }else{
      this.http.post(this.baseUrl + "/ToDos", this.todoModel).subscribe((response) => {
        console.log(response);
        this.todoModel= {} //Empty our object
        this.getDtos() //Get updated dto list
      });
    }
  }

  getDtos(){
    this.http.get(this.baseUrl + "/ToDos").subscribe((response) => {
      this.todos = response;
      console.log(response);
    });
  }

  onEdit(todo){
    this.todoModel = todo;
    console.log(todo);
  }
}
Validation

In this case we want to disable the submit button in case the user did not enter a description or selected a status. so we add the required attribute to both inputs and add a check on the submit button to see of the form is valid.

  <form #form="ngForm" (ngSubmit)="onSubmit()">
    <div class="row">
      <div class="col-8">
        <input placeholder="Something todo" [(ngModel)]="todoModel.description" name="description"
          class="form-control" required/>
      </div>
      <div class="col-2">
        <select [(ngModel)]="todoModel.status" name="status" required>
          <option value="Pending">Pending</option>
          <option value="In Progress">In Progress</option>
          <option value="Done">Done</option>
          <option value="Cancelled">Cancelled</option>
        </select>
      </div>
      <div class="col-2">
        <button type="submit" class="btn btn-primary  mb-2" [disabled]="!form.form.valid">Save Todo</button>
      </div>
    </div>
  </form>

Now we have a working Angular sample, In this post we discussed :

  • Angular Forms
  • Working with Rest API’s
  • ngFor
  • ngSwitch
  • Form Validation
  • Styling with Angular

Hope this post was helpful, you can find the source code on GitHub, Happy Coding.

Source Code

Taggs:
Write a comment