Sunday, November 13, 2016

Build CRUD Angular 2 app that works with a Web API service

This is a follow up article on a previous post where I talked about using Consuming a RESful API with Angular 2 using angular-cli. In this article I will build an Angular 2 application that is more complete with routing and CRUD services that interact with a remote Web API service.

To proceed with this tutorial, it is assumed that you have the following applications already installed on your computer:
  • node.js
  • angular-cli
The first step is to create an application named ng2-flintstones. Type the following within a working directory in a terminal windows:

ng new ng2-flintones

Change to the newly created directory that houses your application with:

cd ng2-flintones

Start the application with this command:
ng serve

Point your browser to http://localhost:4200. You should see this web page:

image

Open the ng2-flinstones folder in Visual Studio Code. Open app.component.ts and modify the class definition so that it looks like this:

import { Component } from '@angular/core';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  PersonId = 1;
  FirstName = "Fred";
  LastName = "Flintstone";
  Occupation = "Mining Manager";
  Gender = "M";
  Picture =  "
http://flintstones.zift.ca/images/flintstone/fred.png";
}
Modify app.component.html so that it has the following markup:
<p>Person ID: {{PersonId}}</p>
<p>First Name: {{FirstName}}</p>
<p>Last Name: {{LastName}}</p>
<p>Occupation: {{Occupation}}</p>
<p>Gender: {{Gender}}</p>
<p>Picture: <img src="{{Picture}}" alt="{{FirstName}} {{LastName}}" /></p>
Refresh your browser. You will be able to see the data that was initialized in the AppComponent class.
Instead of displaying literal data, let us create a CartoonCharacter class. Enter the following command in a terminal window while in the root folder of your application:

ng generate class CartoonCharacter

The above command produces a CartoonCharacter class file named cartoon-character.ts. Modify CartoonCharacter so that it looks like this:
export class CartoonCharacter {
  PersonId: number;
  FirstName: string;
  LastName: string;
  Occupation: string;
  Gender: string;
  Picture: string;
}
Replace the contents of app.component.ts with the following code:
import { Component } from '@angular/core';
import {CartoonCharacter} from './cartoon-character';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  character: CartoonCharacter = {
    PersonId: 1,
    FirstName: "Fred",
    LastName: "Flintstone",
    Occupation: "Mining Manager",
    Gender: "M",
    Picture:  "
http://flintstones.zift.ca/images/flintstone/fred.png",
  };
}

Now that we introduced a class, we can change app.component.html so that it contains the following markup:
<p>Person ID: {{ character.PersonId}}</p>
<p>First Name: {{ character.FirstName}}</p>
<p>Last Name: {{ character.LastName}}</p>
<p>Occupation: {{ character.Occupation}}</p>
<p>Gender: {{ character.Gender}}</p>
<p>Picture: <img src="{{ character.Picture}}"
  alt="{{ character.FirstName}} {{ character.LastName}}" /></p>
 
Refresh the web page. It should appear just like it did previously. The only difference is that we rendered data from an instance of a CartoonCharacter class.

Add the following HTML to the bottom of the app.component.html file:


<div>
    <p><label>First Name: </label><input value="{{ character.FirstName}}" placeholder="FirstName"></p>
    <p><label>Last Name: </label><input value="{{ character.LastName}}" placeholder="LastName"></p>
    <p><label>Occupation: </label><input value="{{ character.Occupation}}" placeholder="Occupation"></p>
    <p><label>Gender: </label><input value="{{ character.Gender}}" placeholder="M or F"></p>
    <p><label>Picture: </label><input value="{{ character.Picture}}" placeholder="Picture"></p>
</div>



Refresh the page and you will notice that some input boxes were added. Unfortunately, if you edit a data item in the text box it does not change above. We will fix that by implementing 2-way binding using [(ngModel)]. Replace app.component.html with the following:
<p>Person ID: {{character.PersonId}}</p>
<p>First Name: {{character.FirstName}}</p>
<p>Last Name: {{character.LastName}}</p>
<p>Occupation: {{character.Occupation}}</p>
<p>Gender: {{character.Gender}}</p>
<p>Picture: <img src="{{character.Picture}}"
  alt="{{character.FirstName}} {{character.LastName}}" /></p>

<div>
    <p><label>First Name: </label><input [(ngModel)]="character.FirstName" placeholder="FirstName"></p>
    <p><label>Last Name: </label><input [(ngModel)]="character.LastName" placeholder="LastName"></p>
    <p><label>Occupation: </label><input [(ngModel)]="character.Occupation" placeholder="Occupation"></p>
    <p><label>Gender: </label><input [(ngModel)]="character.Gender" placeholder="M or F"></p>
    <p><label>Picture: </label><input [(ngModel)]="character.Picture" placeholder="Picture"></p>
</div>
View page. When you change any of the fields the other data changes.
Create a new folder under app named data. In that folder create a file named dummy-data.ts with following content:

import {CartoonCharacter} from '../cartoon-character';
export const DUMMY_DATA: CartoonCharacter[] = [
  {"PersonId":1,"FirstName":"Fred","LastName":"Flintstone","Occupation":"Mining Manager","Gender":"M","Picture":"
http://flintstones.zift.ca/images/flintstone/fred.png"},
  {"PersonId":2,"FirstName":"Barney","LastName":"Rubble","Occupation":"Mining Assistant","Gender":"M","Picture":"
http://flintstones.zift.ca/images/flintstone/barney.png"},
  {"PersonId":3,"FirstName":"Betty","LastName":"Rubble","Occupation":"Nurse","Gender":"F","Picture":"
http://flintstones.zift.ca/images/flintstone/betty.png"},
  {"PersonId":4,"FirstName":"Wilma","LastName":"Flintstone","Occupation":"Teacher","Gender":"F","Picture":"
http://flintstones.zift.ca/images/flintstone/wilma.png"},
  {"PersonId":5,"FirstName":"Bambam","LastName":"Rubble","Occupation":"Baby","Gender":"M","Picture":"
http://flintstones.zift.ca/images/flintstone/bambam.png"},
  {"PersonId":6,"FirstName":"Pebbles","LastName":"Flintstone","Occupation":"Baby","Gender":"F","Picture":"
http://flintstones.zift.ca/images/flintstone/pebbles.png"},
  {"PersonId":7,"FirstName":"Dino","LastName":"Flintstone","Occupation":"Pet","Gender":"F","Picture":"
http://flintstones.zift.ca/images/flintstone/dino.png"}
]
Add to app.component.ts the following import statement:

import {DUMMY_DATA} from './data/dummy-data';

Add the following instance variable to the AppComponent class:

characters = DUMMY_DATA;


There is a form module that needs to be added to our project because we will be displaying and accepting data from a form. Therefore, find app.module.ts and add to it the following import code at the top of the file:

import { FormsModule} from '@angular/forms'

Also, add FormsModule to the imports array in the same app.module.ts file.

In order to display a collection of cartoon-characters, replace app.component.html with the following markup:

<table *ngIf="characters" border="1">
  <thead>
    <tr>
      <th>Person ID</th>
      <th>First Name</th>
      <th>Last Name</th>
      <th>Occupation</th>
      <th>Gender</th>
      <th>Picture</th>
    </tr>
  </thead>
  <tbody>
    <tr *ngFor="let c of characters; let i=index; ">
      <td>{{c.PersonId}}</td>
      <td>{{c.FirstName}}</td>
      <td>{{c.LastName}}</td>
      <td>{{c.Occupation}}</td>
      <td>{{c.Gender}}</td>
      <td><img src="{{c.Picture}}"
        alt="{{c.FirstName}} {{c.LastName}}" /></td>
    </tr>
  </tbody>
</table>

<p>Person ID: {{character.PersonId}}</p>
<p>First Name: {{character.FirstName}}</p>
<p>Last Name: {{character.LastName}}</p>
<p>Occupation: {{character.Occupation}}</p>
<p>Gender: {{character.Gender}}</p>
<p>Picture: <img src="{{character.Picture}}"
        alt="{{character.FirstName}} {{character.LastName}}" /></p>

<div>
    <p><label>First Name: </label><input [(ngModel)]="character.FirstName" placeholder="FirstName"></p>
    <p><label>Last Name: </label><input [(ngModel)]="character.LastName" placeholder="LastName"></p>
    <p><label>Occupation: </label><input [(ngModel)]="character.Occupation" placeholder="Occupation"></p>
    <p><label>Gender: </label><input [(ngModel)]="character.Gender" placeholder="M or F"></p>
    <p><label>Picture: </label><input [(ngModel)]="character.Picture" placeholder="Picture"></p>
</div>



Now when you view the page once more you will notice that whenever you change a data item in the textbox it also changes above.

We want the user to select a cartoon-character from our list, and have the selected character appear in the details view. Modify the opening <tr> tag by inserting an Angular event binding to its click event, like this:

<tr *ngFor="let c of characters; let i=index;" (click)="onSelect(c)">

In the AppComponent class, replace the character declaration with:

selected: CartoonCharacter;

Now add an onSelect method to AppComponent that sets the selected property to the character the user clicked on.
onSelect(character: CartoonCharacter): void {
    this.selected= character;
}
We will be showing the selected character details in our template. Now, it is still referring to the old character property. Let’s fix the template to bind to the new selected property.

Hide the empty detail with *ngIf

When our app loads we see a list of characters, but a cartoon-character is not selected. The selected property is undefined. That’s why we'll see the following error in the browser’s console:
EXCEPTION: TypeError: Cannot read property 'PersonId' of undefined in [null]
Wrap the HTML cartoon character detail content of our template with a <div>. Then we add the *ngIf built-in directive and set it to the selected property of our component like this:
<div *ngIf="selected">
  <p>Person ID: {{selected.PersonId}}</p>
  <p>First Name: {{selected.FirstName}}</p>
  <p>Last Name: {{selected.LastName}}</p>
  <p>Occupation: {{selected.Occupation}}</p>
  <p>Gender: {{selected.Gender}}</p>
  <p>Picture: <img src="{{selected.Picture}}" alt="{{selected.FirstName}} {{selected.LastName}}" /></p>

  <div>
    <p><label>First Name: </label><input [(ngModel)]="selected.FirstName" placeholder="FirstName"></p>
    <p><label>Last Name: </label><input [(ngModel)]="selected.LastName" placeholder="LastName"></p>
    <p><label>Occupation: </label><input [(ngModel)]="selected.Occupation" placeholder="Occupation"></p>
    <p><label>Gender: </label><input [(ngModel)]="selected.Gender" placeholder="M or F"></p>
    <p><label>Picture: </label><input [(ngModel)]="selected.Picture" placeholder="Picture"></p>
  </div>
</div>

CSS

Let us change the background color for a row when it is selected. Add the following CSS into the app.component.css file:
.selected {
  background-color: #CFD8DC !important;
  color: darkblue;
}
In app.component.html, add the following to the <tr> tag that manages the iteration:

[class.selected]="c === selected"

The <tr> tag would look like this:

<tr *ngFor="let c of characters; let i=index;" (click)="onSelect(c)" [class.selected]="c === selected">

Separating the character details

Add a new details component with the following terminal command:

ng generate component CharacterDetail

This produces the following files:
src\app\character-detail\character-detail.component.css
src\app\character-detail\character-detail.component.html
src\app\character-detail\character-detail.component.spec.ts
src\app\character-detail\character-detail.component.ts
In character-detail.component.ts, modify the import statement so that it also imports “Input” as follows:

import { Component, OnInit, Input } from '@angular/core';

Move the whole <div> block that contains detail information from the app.component.html file to the character-detail.component.html file. Do a search and replace from “selected.” to “character.”. The contents of character-detail.component.html will look like this:

<div *ngIf="character">
  <p>Person ID: {{character.PersonId}}</p>
  <p>First Name: {{character.FirstName}}</p>
  <p>Last Name: {{character.LastName}}</p>
  <p>Occupation: {{character.Occupation}}</p>
  <p>Gender: {{character.Gender}}</p>
  <p>Picture: <img src="{{character.Picture}}" alt="{{character.FirstName}} {{character.LastName}}" /></p>

  <div>
    <p><label>First Name: </label><input [(ngModel)]="character.FirstName" placeholder="FirstName"></p>
    <p><label>Last Name: </label><input [(ngModel)]="character.LastName" placeholder="LastName"></p>
    <p><label>Occupation: </label><input [(ngModel)]="character.Occupation" placeholder="Occupation"></p>
    <p><label>Gender: </label><input [(ngModel)]="character.Gender" placeholder="M or F"></p>
    <p><label>Picture: </label><input [(ngModel)]="character.Picture" placeholder="Picture"></p>
  </div>
</div>

Add the cartoon-character property

Add a character property to the CharacterDetailComponent component class:
@Input()
character: CartoonCharacter;
Also, import the CartoonCharacter class with the following import statement.

import {CartoonCharacter} from '../cartoon-character';

The CharacterDetailComponent class must be told what cartoon-character to display by the parent AppComponent class. This will be placed in the <app-character-detail> tag as follows:

<app-character-detail [character]="selected"></app-character-detail>

We will update app.component.html with this later. Meantime, annotate the character property with the @Input decorator that we imported earlier.

Refresh the AppComponent

Open app.component.html and replace the <div> tag that is responsible for displaying selected data with the following:

<app-character-detail [character]="selected"></app-character-detail>

The app.component.html file should now look like this:
<table *ngIf="characters" border="1">
  <thead>
    <tr>
      <th>Person ID</th>
      <th>First Name</th>
      <th>Last Name</th>
      <th>Occupation</th>
      <th>Gender</th>
    </tr>
  </thead>
  <tbody>
    <tr *ngFor="let c of characters; let i=index;" (click)="onSelect(c)" [class.selected]="c === selected">
      <td>{{c.PersonId}}</td>
      <td>{{c.FirstName}}</td>
      <td>{{c.LastName}}</td>
      <td>{{c.Occupation}}</td>
      <td>{{c.Gender}}</td>
    </tr>
  </tbody>
</table>
<app-character-detail [character]="selected"></app-character-detail>
Check the web application in your browser and make sure that it works and behaves just as it did before we separated out the details about our characters.

Creating a CartoonCharacter service

Next, we will create a cartoon-character service that can be used from a multitude of components. To this end, execute the following instruction from a terminal window while in the root folder:

ng generate service CartoonCharacter

This produces the following files:
src\app\cartoon-character.service.spec.ts
src\app\cartoon-character.service.ts
Add an empty getCartoonCharacters() method to the CartoonCharacterService class as follows:

getCartoonCharacters(): void { }

Add the following import commands to the new service cartoon-character.service.ts file:
import {DUMMY_DATA} from './data/dummy-data';
import {CartoonCharacter} from './cartoon-character'
In app.component.ts, change ‘characters = DUMMY_DATA;’ to ‘characters: CartoonCharacter[];’ and delete the DUMMY_DATA import statement. The app.component.ts should look like this:

import { Component } from '@angular/core';
import {CartoonCharacter} from './cartoon-character';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  /*
  character: CartoonCharacter = {
    PersonId: 1,
    FirstName: "Fred",
    LastName: "Flintstone",
    Occupation: "Mining Manager",
    Gender: "M",
    Picture:  "
http://flintstones.zift.ca/images/flintstone/fred.png",
  };
  */

  selected: CartoonCharacter;
  characters: CartoonCharacter[];
  onSelect(character: CartoonCharacter): void {
    this.selected = character;
  }
}


In the CartoonCharacterService class, replace the getCartoonCharacters() method with the following code:
getCartoonCharacters(): CartoonCharacter[] {  
  return DUMMY_DATA;
}
The cartoon-character.service.ts file now should look like this:
import { Injectable } from '@angular/core';
import {DUMMY_DATA} from './data/dummy-data';
import {CartoonCharacter} from './cartoon-character'

@Injectable()
export class CartoonCharacterService {

  constructor() { }
  getCartoonCharacters(): CartoonCharacter[] {  
    return DUMMY_DATA;
  }
}

Using the CartoonCharacter service

We will be using the new service in app.component.ts. Back in that file, import the service with the following statement:

import {CartoonCharacterService} from './cartoon-character.service';

We do not want to instantiate a new instance of CartoonCharacterService. Instead, we will use dependency injection. Add the following constructor to the AppComponent class:

constructor(private cartoonService: CartoonCharacterService) { }

Add the following providers array to @Component for the AppComponent class:
providers: [CartoonCharacterService]
Add the following method to AppComponent:
getCartoonCharacters(): void {
  this.characters = this.cartoonService.getCartoonCharacters();
}
Instead of making a call to getCartoonCharacters() from within the constructor of AppComponent, we will make a call when the component gets initialized. This is best done in the ngOnInit() method.

To do this we need to import OnInit and implement OnInit. We will then make a call to getCartoonCharacters() from within the ngOnInit() method. Here’s what app.component.ts should now look like:

import { Component, OnInit } from '@angular/core';
import {CartoonCharacter} from './cartoon-character';
import {CartoonCharacterService} from './cartoon-character.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  providers: [CartoonCharacterService]
})
export class AppComponent implements OnInit {
  selected: CartoonCharacter;
  characters: CartoonCharacter[];

  constructor(private cartoonService: CartoonCharacterService) { }
  onSelect(character: CartoonCharacter): void {
    this.selected = character;
  }

  getCartoonCharacters(): void {
    this.characters = this.cartoonService.getCartoonCharacters();
  }

  ngOnInit(): void {
    this.getCartoonCharacters();
  }
}


Our application should be working fine now.

There is one problem, though. Our service is not making async calls. We will change that. Change the getCartoonCharacters() method in the CartoonCharacterService class to the following:
getCartoonCharacters(): Promise<CartoonCharacter[]> {  
  return Promise.resolve(DUMMY_DATA);
}
Since this returns a promise, we will need to change the way this method is called. Back in AppComponent class, change the getCartoonCharacters() method to the following:
getCartoonCharacters(): void {
this.cartoonService.getCartoonCharacters()
  .then(characters => this.characters = characters);
}

Routing around our app

We will build a menu system with links allowing us to choose what it is we want to do. Now, we only have one page. This is not very realistic for a larger project. Our revised app should display a shell with a choice of views (Dashboard and Cartoon Characters) and then default to one of them. The first task is to move the display of cartoon-characters out of AppComponent and into its own CartoonCharacterComponent.

Let us create a new component named CartoonCharacterComponent with the following terminal command:

ng generate component CartoonCharacter

The following files get generated:
src\app\cartoon-character\cartoon-character.component.css
src\app\cartoon-character\cartoon-character.component.html
src\app\cartoon-character\cartoon-character.component.spec.ts
src\app\cartoon-character\cartoon-character.component.ts
Since AppComponent is doing the work that we want CartoonCharacterComponent to do, let us simply copy the contents of AppComponent to CartoonCharacterComponent:
|
Copy Contents from … to …
app.component.html cartoon-character.html
app.component.css cartoon-character.css
app.component.ts cartoon-character.ts
Also:
  • change the app-root selector in copied contents of cartoon-character.component.ts to cartoon-character-component
  • delete the providers array line – providers: [CartoonCharacterService]
  • adjust the filenames in cartoon-character.component.ts to match the actual .html and .css files
  • app.component.html should contain only the following markup:
<cartoon-character-component></cartoon-character-component>

Make sure the content of app.component.ts has the following code’:

import { Component } from '@angular/core';
import { CartoonCharacterService } from './cartoon-character.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  providers: [CartoonCharacterService]
})
export class AppComponent {
  title = 'The Flintstones';
}

Check out the application, it should be working fine just like before.

Routing

The next big task is to add routes and links to our main landing page. Open app.module.ts in your editor and add the following import statement:

import { RouterModule } from '@angular/router';

Define our first route by adding the following to the imports array:
RouterModule.forRoot([
  {
    path: 'characters',
    component: CartoonCharacterComponent
  }
])
app.module.ts now looks like this:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';
import { CharacterDetailComponent } from './character-detail/character-detail.component';
import { CartoonCharacterComponent } from './cartoon-character/cartoon-character.component';

import { RouterModule } from '@angular/router';
@NgModule({
  declarations: [
    AppComponent,
    CharacterDetailComponent,
    CartoonCharacterComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    RouterModule.forRoot([
      {
        path: 'characters',
        component: CartoonCharacterComponent
      }
    ])
  ],
  providers: [],
  bootstrap: [AppComponent],
 
})
export class AppModule { }


The route definition has the following parts:
  • path: the router matches this route's path to the URL in the browser address bar (characters).
  • component: the component that the router should create when navigating to this route (CartoonCharacterComponent).

Router Outlet

If we paste the path, /characters, into the browser address bar, the router should match it to the characters route and display the CartoonCharacterComponent. But where?

We must tell it where by adding a <router-outlet> element to the bottom of the template. The router displays each component immediately below the <router-outlet> as we navigate through the application.

Edit the app.component.html file. Replace <cartoon-characters></cartoon-characters> with the following markup:
<nav>
    <a routerLink="/characters">Cartoon Characters</a>
</nav>
<router-outlet></router-outlet>
When you run the application, you will see a link as follows:

image

When you click on the “Cartoon Characters” link, two things happen:
  1. The address line in your browser changes to: http://localhost:4200/characters
  2. The contents of CartoonCharacterComponent are injected into <router-outlet></router-outlet>

Adding another dashboard link

Create another component named DashboardComponent by executing the following in a terminal window:

ng generate component Dashboard

This causes the following files to be created for us:
src\app\dashboard\dashboard.component.css
src\app\dashboard\dashboard.component.html
src\app\dashboard\dashboard.component.spec.ts
src\app\dashboard\dashboard.component.ts
Add another route to app.module.ts as shown below:
{
  path: 'dashboard',
  component: DashboardComponent
},
Next, let us add one more link to app.component.html. Our latest iteration of app.component.html looks like this:
<h1>{{title}}</h1>
<nav>
  <a routerLink="/dashboard">Dashboard</a>
    <a routerLink="/characters">Cartoon Characters</a>
</nav>
<router-outlet></router-outlet>
At this point, when you run the application this is what you should see:

image

Of course, we still need to develop our DashboardComponent class. Modify dashboard.component.ts so that it looks like this:

import { Component, OnInit } from '@angular/core';
import {CartoonCharacter} from '../cartoon-character';
import {CartoonCharacterService} from '../cartoon-character.service';
@Component({
  selector: 'app-dashboard',
  templateUrl: './dashboard.component.html',
  styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent implements OnInit {
  characters: CartoonCharacter[];

  constructor(private cartoonService: CartoonCharacterService) { }
  ngOnInit() {
    this.cartoonService.getCartoonCharacters()
      .then(results => this.characters = results.slice(0, 4));
 
}
}

Also, modify dashboard.component.html so that it looks like this:

<h3>The Flintstones Family</h3>
<p *ngFor="let c of characters" class="col-lg-4">
      {{c.FirstName}} {{c.LastName}}
</p>
Refresh the browser and see four cartoon characters in the new dashboard as shown below:

image

Click on “Cartoon Characters” and you will see our table with details.

Routing to our Cartoon Character details

One refinement that is overdue is to navigate to a details page if the user clicks on a character on our dashboard.

We need to add an additional method to CartoonCharacterService that retrieves a single record by id. Open CartoonCharacterService and add a getCartoonCharacterById() method that filters the cartoon-characters list from getCartoonCharacters() by id:

getCartoonCharacterById(id: number): Promise<CartoonCharacter> {
  return this.getCartoonCharacters()
    .then(result => result.find(character => character.PersonId === id));
}


We'll add a route to the CharacterDetailComponent in app.module.ts where our other routes are configured. Add the following route definition to app.module.ts:
{
  path: 'detail/:id',
  component: CharacterDetailComponent
},
The colon (:) in the path indicates that :id is a placeholder to be filled with a specific cartoon character id when navigating to the CharacterDetailComponent.

The revised CharacterDetailComponent should take the id parameter from the params observable in the ActivatedRoute service and use the CartoonCharacterService to fetch the cartoon character with that id.

Add the following import statements to character-detail.component.ts:

import { ActivatedRoute, Params }   from '@angular/router';
import { Location }                 from '@angular/common';
import { CartoonCharacterService } from '../cartoon-character.service';


Let's have the ActivatedRoute, CartoonCharacterService and Location services injected into the constructor, saving their values in private fields:
constructor(
  private cartoonService: CartoonCharacterService,
  private route: ActivatedRoute,
  private location: Location
) { }
Inside the ngOnInit lifecycle method, we use the params observable to extract the id parameter value from the ActivatedRoute service and use the CartoonCharacterService to fetch the cartoon-character with that id.
ngOnInit() {
  this.route.params.forEach((params: Params) => {
    let id = +params['id'];
    this.cartoonService.getCartoonCharacterById(id)
      .then(result => this.character = result);
  });
}
Notice how we extract the id by calling the forEach method, which will deliver our array of route parameters. The cartoon character id is a number. Route parameters are always strings. So, we convert the route parameter value to a number with the JavaScript (+) operator.

Also, add this method to character-detail.component.ts so that we can go back:
goBack(): void {
  this.location.back();
}
Add the following markup to character-detail.component.html so that it now looks like this:

<div *ngIf="character">
  <p>Person ID: {{character.PersonId}}</p>
  <p>First Name: {{character.FirstName}}</p>
  <p>Last Name: {{character.LastName}}</p>
  <p>Occupation: {{character.Occupation}}</p>
  <p>Gender: {{character.Gender}}</p>
  <p>Picture: <img src="{{character.Picture}}" alt="{{character.FirstName}} {{character.LastName}}" /></p>

  <div>
    <p><label>First Name: </label><input [(ngModel)]="character.FirstName" placeholder="FirstName"></p>
    <p><label>Last Name: </label><input [(ngModel)]="character.LastName" placeholder="LastName"></p>
    <p><label>Occupation: </label><input [(ngModel)]="character.Occupation" placeholder="Occupation"></p>
    <p><label>Gender: </label><input [(ngModel)]="character.Gender" placeholder="M or F"></p>
    <p><label>Picture: </label><input [(ngModel)]="character.Picture" placeholder="Picture"></p>
  </div>
  <button (click)="goBack()">Back</button>
</div>


When a user selects a cartoon-character on the dashboard, the app should navigate to the CharacterDetailComponent to view and edit the selected cartoon-character.

To achieve this effect, reopen the dashboard.component.html and replace the repeated <div *ngFor...> tags with <a> tags so that it looks like this:

<h3>The Flintstones Family</h3>
<a *ngFor="let c of characters"  [routerLink]="['/detail', c.PersonId]"  class="col-lg-4">
  <p>{{c.FirstName}} {{c.LastName}}</p>
</a>

Refresh the browser and select a cartoon-character from the dashboard; the app should navigate directly to that cartoon-character’s details.

imageimage

Clicking on the “Back” button will take you back in the history of the browser.

Refactor routes to a Routing Module

It is wise to put all of our routing rules in a separate file than app.module.ts so it does not get overly bloated. This is especially true if our application is large and has many routes. To this end, create an app-routing.module.ts file in the same folder as app.module.ts. Give it the following contents extracted from the AppModule class:

import { NgModule }             from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { DashboardComponent }   from './dashboard/dashboard.component';
import { CartoonCharacterComponent } from './cartoon-character/cartoon-character.component';
import { CharacterDetailComponent } from './character-detail/character-detail.component';

const routes: Routes = [
  { path: '', redirectTo: '/dashboard', pathMatch: 'full' },
  { path: 'dashboard',  component: DashboardComponent },
  { path: 'detail/:id', component: CharacterDetailComponent },
  { path: 'characters',     component: CartoonCharacterComponent }
];

@NgModule({
  imports: [ RouterModule.forRoot(routes) ],
  exports: [ RouterModule ]
})
export class AppRoutingModule {}


Next, let’s update app.module.ts so that it uses app-routing.module.ts. Add the following import statement to app.module.ts.

import { AppRoutingModule } from './app-routing.module';

Also, change the imports array so it looks like this:

imports: [
  BrowserModule,
  FormsModule,
  HttpModule,
  AppRoutingModule
],


This would be the latest state of app.module.ts:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';
import { CharacterDetailComponent } from './character-detail/character-detail.component';
import { CartoonCharacterComponent } from './cartoon-character/cartoon-character.component';

import { RouterModule } from '@angular/router';
import { DashboardComponent } from './dashboard/dashboard.component';

import { AppRoutingModule } from './app-routing.module';
@NgModule({
  declarations: [
    AppComponent,
    CharacterDetailComponent,
    CartoonCharacterComponent,
    DashboardComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent],

})
export class AppModule { }


Our application functions properly and behaves as expected.


Select a Cartoon-Character in the CartoonCharacterComponent

Comment out the last line in cartoon-character.component.html so that it looks like this:

<!--
<app-character-detail [character]="selected"></app-character-detail>
-->


When the user selects a cartoon-character from the list, we don't go to the detail page. We show a mini-detail on this page instead and make the user click a button to navigate to the full detail page.

Add the following HTML fragment at the bottom of cartoon-character.component.html:

<div *ngIf="selected">
  <h2>
    {{selected.FirstName | uppercase}} {{selected.LastName | uppercase}} is favorite cartoon character.
  </h2>
  <button (click)="gotoDetail()">View Details</button>
</div>


Update the Update the CartoonCharacterComponent class as follows:
    1. Import Router from the Angular router library with the following import statement: 
     
    import { Router } from '@angular/router';

    2. Inject the Router in the constructor (along with the CartoonCharacterService) as follow: 
     
    constructor(
      private cartoonService: CartoonCharacterService,
      private router: Router
    ) { }
    3. Implement gotoDetail() by calling the router.navigate method as shown below:
    gotoDetail(): void {
      this.router.navigate(['/detail', this.selected.PersonId]);
    }
Refresh your browser and checkout the new behavior of the application.

Styling:

Replace dashboard.component.css with the following:
label {
  display: inline-block;
  width: 3em;
  margin: .5em 0;
  color: #607D8B;
  font-weight: bold;
}
input {
  height: 2em;
  font-size: 1em;
  padding-left: .4em;
}
button {
  margin-top: 20px;
  font-family: Arial;
  background-color: #eee;
  border: none;
  padding: 5px 10px;
  border-radius: 4px;
  cursor: pointer; cursor: hand;
}
button:hover {
  background-color: #cfd8dc;
}
button:disabled {
  background-color: #eee;
  color: #ccc;
  cursor: auto;
}
Replace contents of cartoon-character.component.css with the following:
label {
  display: inline-block;
  width: 3em;
  margin: .5em 0;
  color: #607D8B;
  font-weight: bold;
}
input {
  height: 2em;
  font-size: 1em;
  padding-left: .4em;
}
button {
  margin-top: 20px;
  font-family: Arial;
  background-color: #eee;
  border: none;
  padding: 5px 10px;
  border-radius: 4px;
  cursor: pointer; cursor: hand;
}
button:hover {
  background-color: #cfd8dc;
}
button:disabled {
  background-color: #eee;
  color: #ccc;
  cursor: auto;
}
Replace contents of app.component.css with the following:
h1 {
  font-size: 1.2em;
  color: #999;
  margin-bottom: 0;
}
h2 {
  font-size: 2em;
  margin-top: 0;
  padding-top: 0;
}
nav a {
  padding: 5px 10px;
  text-decoration: none;
  margin-top: 10px;
  display: inline-block;
  background-color: #eee;
  border-radius: 4px;
}
nav a:visited, a:link {
  color: #607D8B;
}
nav a:hover {
  color: #039be5;
  background-color: #CFD8DC;
}
nav a.active {
  color: #039be5;
}
To set the global application styles, replace contents of styles.css with:
/* Master Styles */
h1 {
  color: #369;
  font-family: Arial, Helvetica, sans-serif;
  font-size: 250%;
}
h2, h3 {
  color: #444;
  font-family: Arial, Helvetica, sans-serif;
  font-weight: lighter;
}
body {
  margin: 2em;
}
body, input[text], button {
  color: #888;
  font-family: Cambria, Georgia;
}
/* . . . */
/* everywhere else */
* {
  font-family: Arial, Helvetica, sans-serif;
}

Navigate through the application and experience the refined look.

Working with real data

The data we are viewing is being served from a static array. We need to interact with a real remote service. We will work with a service located at http://flintstones.zift.ca/flintstones/ that delivers the same data as the static array used previously.

Let's convert getCartoonCharacters () in cartoon-character.ts to use HTTP. Add the following import statements to cartoon-character.service.ts:
import { Headers, Http, Response } from '@angular/http';
import 'rxjs/add/operator/toPromise';
import 'rxjs/add/operator/map';
Inject the http service into the service’s constructor with the following code:

constructor(private http: Http) { }

Add the following instance variable to the CartoonCharacterService class:

private BASE_URL = "http://flintstones.zift.ca/api/flintstones";

Change method getCartoonCharacters() in cartoon-character.service.ts to the following code:
getCartoonCharacters(): Promise<CartoonCharacter[]> {
  return this.http.get(this.BASE_URL)
   .toPromise()
   .then(response => response.json() as CartoonCharacter[])
   .catch(this.handleError);
}
The catch block calls a handleError() method. Add this handleError() method to the CartoonCharacterService class:

private handleError(error: any): Promise<any> {
  console.error('An error occurred', error); // for demo purposes only
  return Promise.reject(error.message || error);
}


Test the application and you will determine that it works just as before. The big difference is that it is indeed asynchronously retrieving data from a remote data source.

Updating data

The next challenge is to update data. Add the following code to the CartoonCharacterService class:

private headers = new Headers({'Content-Type': 'application/json'});
update(character: CartoonCharacter): Promise<CartoonCharacter> {
  const url = `${this.BASE_URL}/${character.PersonId}`;
  return this.http
    .put(url, JSON.stringify(character), {headers: this.headers})
    .toPromise()
    .then(() => character)
    .catch(this.handleError);
}


Add the following save button to the bottom of the character-detail.component.html file right after the back button:

&nbsp;&nbsp;&nbsp;&nbsp;<button (click)="save()">Save</button>

The save method persists cartoon-character data changes using the service’s update method, then navigates back to the previous view. Add this save() method to character-detail.component.ts:
save(): void {
  this.cartoonService.update(this.character)
    .then(() => this.goBack());
}
Refresh the browser and give it a try. Changes to cartoon-character data should now persist.

Add data

Add the following method to the CartoonCharacterService class:

create(newCartoonCharacter: CartoonCharacter): Promise<CartoonCharacter> {
  return this.http
    .post(this.BASE_URL, JSON.stringify(newCartoonCharacter), {headers: this.headers})
    .toPromise()
    .then(res => res.json().data)
    .catch(this.handleError);
}


Add this markup to cartoon-character.component.html:

<div>
  <p><label>First Name: </label><input [(ngModel)]="newCharacter.FirstName" placeholder="First Name"></p>
  <p><label>Last Name: </label><input [(ngModel)]="newCharacter.LastName" placeholder="Last Name"></p>
  <p><label>Occupation: </label><input [(ngModel)]="newCharacter.Occupation" placeholder="Occupation"></p>
  <p><label>Gender: </label><input [(ngModel)]="newCharacter.Gender" placeholder="M or F"></p>
  <p><label>Picture: </label><input [(ngModel)]="newCharacter.Picture" placeholder="Picture URL"></p>
  <button (click)="add(newCharacter);">
    Add
  </button>
</div>


Add the following to the CartoonCharacterComponent class:

newCharacter: CartoonCharacter = new CartoonCharacter();
add(newCartoonCharacter: CartoonCharacter): void {
  newCartoonCharacter.FirstName = newCartoonCharacter.FirstName.trim();
  newCartoonCharacter.LastName = newCartoonCharacter.LastName.trim();
  newCartoonCharacter.Occupation = newCartoonCharacter.Occupation.trim();
  newCartoonCharacter.Gender = newCartoonCharacter.Gender.trim();
  newCartoonCharacter.Picture = newCartoonCharacter.Picture.trim();
 
  if (!newCartoonCharacter) { return; }

  this.cartoonService.create(newCartoonCharacter)
    .then(newCartoonCharacter => {
      this.selected = null;
      this.router.navigate(['./dashboard']);
    });
}


Refresh the browser and add some sample cartoon-character data.

Deleting data

Add a new column to the table in cartoon-character.component.html and put the following button in a cell after {{c.Gender}}:

<button class="delete" (click)="delete(c); $event.stopPropagation()">x</button>

The entire table in cartoon-character.component.html will look like this:

<table *ngIf="characters" border="1">
  <thead>
    <tr>
      <th>Person ID</th>
      <th>First Name</th>
      <th>Last Name</th>
      <th>Occupation</th>
      <th>Gender</th>
      <th></th>
    </tr>
  </thead>
  <tbody>
    <tr *ngFor="let c of characters; let i=index;" (click)="onSelect(c)" [class.selected]="c === selected">
      <td>{{c.PersonId}}</td>
      <td>{{c.FirstName}}</td>
      <td>{{c.LastName}}</td>
      <td>{{c.Occupation}}</td>
      <td>{{c.Gender}}</td>
      <td><button class="delete" (click)="delete(c); $event.stopPropagation()">x</button></td>
    </tr>
  </tbody>
</table>


Add the following delete() method to the CartoonCharacterService class:
delete(id: number): Promise<void> {
  const url = `${this.BASE_URL}/${id}`;
  return this.http.delete(url, {headers: this.headers})
    .toPromise()
    .then(() => null)
    .catch(this.handleError);
}
Add this delete() method to the CartoonCharacterComponent class:

delete(delCharacter: CartoonCharacter): void {
  this.cartoonService
      .delete(delCharacter.PersonId)
      .then(() => {
        this.characters = this.characters.filter(c => c !== delCharacter);
        if (this.selected === delCharacter) { this.selected = null; }
      });
}


Refresh the browser and try the new delete the records that you created.

Conclusion

In this post, we have developed a well structured Angular 2 application that interacts with real data. If you and retrieve, add, update, and delete data then you are in a position to do some true an real world single page applications with Angular 2.

References:

https://angular.io/docs/ts/latest/tutorial/






















































































































































Saturday, November 12, 2016

Consuming a RESful API with Angular 2 using angular-cli

Angular-cli is a command line interface used to scaffold and build angular2 apps using nodejs style (commonJs) modules. In this tutorial I will build a simple Angular 2 application that consumes a posts RESful API service located at https://jsonplaceholder.typicode.com/posts. This API service belongs to a handful APIs that are available for developers and testers at https://jsonplaceholder.typicode.com/.

Here’s a sample of what you will see if you point your browser to https://jsonplaceholder.typicode.com/posts:

image

The Post object looks like this:
{
  "userId": "number",
  "id": "number",
  "title": "string",
  "body": "string"
}
To continue with this tutorial, you will need to install node.js on your computer, If you do not already have it installed then download and install it from https://nodejs.org.

Once you have installed node.js, then go to a command prompt (or terminal window) and run the following command to globally install angular-cli:

npm install -g angular-cli

This may take some time so be patient. Although you can ignore warnings, if you get any red error messages then try the following:
  • run your command prompt in admin mode. If you are using linux or mac then use sudo
  • otherwise, try to upgrade to the latest version of node.js on tour computer.
Upon successful installation of angular-cli, you can now go ahead an scaffold an angular2 app that serves as a suitable starting point. Go to a convenient working directory and execute the following command to create an app named ng2-posts:

ng new ng2-posts

This also takes some time so patience is a good asset. Once the scaffolding process is complete, let’s see what it looks like. Change into the newly created ng2-posts directory:

cd ng2-posts

To build the application, run the following command:

ng build

To host the web application under a light-weight web server listening on port 4200, run the following command:
ng serve

Note: The ng serve command also builds the application so the ng build step is rather optional.

You can now view the web page in your browser by going to http://localhost:4200. This is what you will see:

image

Let us have a look at all the files that were generated. Load the contents of the ng2-posts folder into Visual Studio Code, which can be downloaded from http://code.visualstudio.com/. This is what the source code looks like:

image

Tip: You can load the application in Visual Studio Code by simply running the command “code .” from inside the main application directory within a terminal window.

Since we will need a Post class to represent our object, we can use angular-cli to create it for us. Type in the following command in a terminal window while in the main ng2-posts folder:

ng generate class Post

This results in the creation of a TypeScript file src\app\post.ts that has the following content:
export class Post {
}
Replace the content of post.ts with the following code:
export class Post {
  userId: number;
  id: number;
  title: string;
  body: string;
  constructor(obj?: any) {
    this.userId = obj && obj.userId || null;
    this.id = obj && obj.id || null;
    this.title = obj && obj.title || null;
    this.body = obj && obj.body || null;
  }
}
Next, we need to create a service that is responsible for all http requests to the RESTful API. Type in the following command in a terminal window while in the main ng2-posts folder:

ng generate service Post

This results in the creation of two TypeScript files:  src\app\post.service.spec.ts & src\app\post.service.ts.

Note:
  • The convention for naming a service is {service name}.service.ts. This is also applied to naming components as {component name}.component.ts.
  • The post.service.spec.ts is the unit test file.
The generated post.service.ts file looks like this:
import { Injectable } from '@angular/core';
@Injectable()
export class PostService {

  constructor() { }
}
Replace the contents of post.service.ts with the following:
import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import 'rxjs/add/operator/map';

@Injectable()
export class PostService {

  constructor(private http: Http) { }
  getAll() {
    return this.http.get('
https://jsonplaceholder.typicode.com/posts')
    .map((res: Response) => res.json());
  }
}
The above class is annotated with @Injectable() so that it can be used in dependency injection. In order for this to be possible, we will need to make it a provider at a higher level component. In this case, we will add it as a provider in the app.component.ts class. Edit app.component.ts and add the following import command in line 2:

import { PostService } from "./post.service";

Add the following to the @Component block:

providers: [PostService]

The AppComponent class then looks like this:
import { Component } from '@angular/core';
import { PostService } from "./post.service"

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  providers: [PostService]
})
export class AppComponent {
  title = 'app works!';
}
The next step is to create a Post component that actually uses the service that we created and displays some data in HTML. Create a PostComponent class by running the following command in a terminal window while in the main ng2-posts folder:

ng generate component Post

This results in the creation the following files:
src\app\post\post.component.css
src\app\post\post.component.html
src\app\post\post.component.spec.ts
src\app\post\post.component.ts
Note the following:
  • The component files follow the convention mentioned previously and are placed in a dedicated folder named post.
  • The third file (post.component.spec.ts) is for unit testing purposes.
Open the post.component.html and view its contents:
<p>
  post works!
</p>
Also, look at the contents of post.component.ts:
import { Component, OnInit } from '@angular/core';
@Component({
  selector: 'app-post',
  templateUrl: './post.component.html',
  styleUrls: ['./post.component.css']
})
export class PostComponent implements OnInit {
  constructor() { }

  ngOnInit() { }
}
The above suggests that if we place the tag <app-post></app-post> in a consuming component class, then it will display “Post works!”. Let us test this out. Open app.component.ts in your editor and add the following import statement in line 3:

import { PostComponent } from "./post/post.component";

The app.component.ts would then look like this:
import { Component } from '@angular/core';
import { PostService } from "./post.service";
import { PostComponent } from "./post/post.component";

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  providers: [PostService]
})
export class AppComponent {
  title = 'app works!';
}
Now let us add the <app-post></app-post> markup inside app.component.html so it looks like this:
<h1>
  {{title}}
</h1>
<app-post></app-post>
Have a peek at the web page. It should look like this:

image

What we just proved is that a custom component can be easily used by another component. Let us now enhance PostComponent so that it displays posts with real remote data coming from a RESTful service. Open post.component.ts in your editor and replace its contents with the following code:
import { Component, OnInit } from '@angular/core';
import {Post} from '../post';
import {PostService} from '../post.service';

@Component({
  selector: 'app-post',
  templateUrl: './post.component.html',
  styleUrls: ['./post.component.css']
})
export class PostComponent implements OnInit {
  results: Array<Post>;

  constructor(private postService: PostService) { }
  ngOnInit() {
    this.postService.getAll().subscribe(
      data => { this.results = data; },
      error => console.log(error)
    );
  }
}
Note the following about the above code:
  • Both Post class and PostService must first get imported.
  • PostService is being injected into the constructor making its instance available to the rest of the class. This is possible because of dependency injection and the fact that we previously added it as a provider inside app.component.ts.
  • The ngOnInit() method runs after the class is initialized. It calls the service’s getAll() method and hydrates the results array of Post objects with actual data coming from the RESTful API service.
The last step is to render data into our HTML view. Open post.component.html and replace its content with the following:
<table *ngIf="results" border="1">
  <thead>
    <tr>
      <th>User ID</th>
      <th>ID</th>
      <th>Title</th>
      <th>Body</th>
    </tr>
  </thead>
  <tbody>
    <tr *ngFor="let p of results; let i=index">
      <td>{{p.userId}}</td>
      <td>{{p.id}}</td>
      <td>{{p.title}}</td>
      <td>{{p.body}}</td>
    </tr>
  </tbody>
</table>
The hour of truth is at hand. View the web page in your browser. It should resemble this:

image

This should be a great starting point for you to appreciate Angular 2 and do more interesting things with it.

References:

https://dzone.com/articles/getting-started-and-testing-with-angular-cli-and-angular-2-rc5-part-1
https://www.sitepoint.com/angular-2-tutorial/
http://www.mithunvp.com/build-angular-apps-using-angular-2-cli/

Saturday, November 5, 2016

Xamarin Forms Client for Azure ASP.NET Web API service

Xamarin Forms allows for the development of mobile apps using C# with a single code base for deployment to Android, iOS, and Windows.

It is advisable that you watch this video on Channel 9 in order to properly setup your Visual Studio 2015 environment for Xamarin development:

https://channel9.msdn.com/series/tendulkar-uvca/0102-Verify-Machine-Setup

Overview

The objective of this tutorial is to consume a Web API service. In this tutorial, we will use a service at http://cartoonapi.azurewebsites.net/api/cartoon. If you point your browser to this address, the JSON response will look like this:

[{"name":"Aladdin","pictureUrl":"images/aladdin.png"},
{"name":"Bambam Rubble","pictureUrl":"images/bambam_rubble.png"},
{"name":"Bambi","pictureUrl":"images/bambi.png"},
{"name":"Barney Rubble","pictureUrl":"images/barney_rubble.png"},
{"name":"Betty Flintstone","pictureUrl":"images/betty_flintstone.png"},
{"name":"Dino","pictureUrl":"images/dino.png"},
{"name":"Donald Duck","pictureUrl":"images/donald_duck.png"},
{"name":"Flintstone Family","pictureUrl":"images/flintstone_family.png"},
{"name":"Flounder","pictureUrl":"images/Flounder.png"},
{"name":"Fred Flinrstone","pictureUrl":"images/fred_flinrstone.png"},
{"name":"Goofy","pictureUrl":"images/Goofy.png"},
{"name":"Jasmine","pictureUrl":"images/jasmine.png"},
{"name":"Jumbo","pictureUrl":"images/jumbo.png"},
{"name":"Mermaid","pictureUrl":"images/mermaid.png"},
{"name":"Micky Mouse","pictureUrl":"images/micky_mouse.png"},
{"name":"Minnie Mouse","pictureUrl":"images/minnie_mouse.png"},
{"name":"Pebbles Flintstone","pictureUrl":"images/pebbles_flintstone.png"},
{"name":"Peter Pan","pictureUrl":"images/peter_pan.png"},
{"name":"Pinocchio","pictureUrl":"images/pinocchio.png"},
{"name":"Pluto","pictureUrl":"images/pluto.png"},
{"name":"Simba","pictureUrl":"images/simba.png"},
{"name":"Snow White","pictureUrl":"images/snow_white.png"},
{"name":"Tigger","pictureUrl":"images/tigger.png"},
{"name":"Tinkerbell","pictureUrl":"images/tinkerbell.png"},
{"name":"Tweety","pictureUrl":"images/tweety.png"},
{"name":"Wilma Flintstone","pictureUrl":"images/wilma_flintstone.png"},
{"name":"Winnie The Pooh","pictureUrl":"images/winnie_the_pooh.png"}]


The above JSON collection pertains to cartoon characters with only two properties: Name & PictureUrl.

Creating a Xamarin Forms portable application

Start Visual Studio 2015 then click on:

File >> New >> Project
Templates >> Visual C# >> Cross-Platform >> Blank Xaml App (Xamarin.Forms Portable)

image

Name the application “ComicMobile” then click on OK.

On the “New Universal Windows Project” dialog, choose Build 10586 for both Target and Minimum versions.

image

Be patient, it may take some time to create these six projects:

ComicMobile This is a shared solution
ComicMobile.Droid Android project
ComicMobile.iOS iOS project
ComicMobile.UWP UWP project
ComicMobile.Windows Windows 8.1 project
ComicMobile.WinPhone Windows Phone 8.1 project

Go ahead and remove the last two projects (ComicMobile.Windows & ComicMobile.WinPhone) from the Visual Studio solution in order to keep our project as small as possible. Also, delete the relevant folders for the two projects that you removed from the file system.

Open the configuration manager by selecting Build >> Configuration Manager…

image

Enable Build & Deploy for the UWP project then click on Close.

Right-click on the UWP project and select Build.

Then, right-click again on the UWP application and select “Set as StartUp Project”.

Hit F5 on the keyboard to run the UWP application in debug mode on the “Local Machine”. The application will run and the main window will look like this:

image

Adding a Web API client

Close the running application, then install the following two Nuget package to the “ComicMobile (Portable)” project:

Newtonsoft.Json
Microsoft.Net.Http

Add folders Models and ViewModels to the top “ComicMobile (Portable)” project.

Add a class named CartoonCharacter to the Models folder. In order to put  remote data into a C# collection, replace the CartoonCharacter class definition in the Models folder with the following code:

public class CartoonCharacter {
  public string Name { get; set; }
  public string PictureUrl { get; set; }
}


The code for actually connecting to the remote service and reading data will be placed in a View Model class. Add a class named CartoonViewModel to the ViewModels folder and replace the class definition with the following code:

public class CartoonViewModel : INotifyPropertyChanged {
  const string BASE_URL = "
http://cartoonapi.azurewebsites.net/";
  public event PropertyChangedEventHandler PropertyChanged;
  public Command GetCartoonCharactersCommand { get; set; }

  public ObservableCollection<CartoonCharacter> CartoonCharacters { get; set; }
  public CartoonViewModel() {
      CartoonCharacters = new ObservableCollection<CartoonCharacter>();

      GetCartoonCharactersCommand = new Command(
        async () => await GetCartoonCharacters(),
        () => !IsBusy);
  }

  private void OnPropertyChanged([CallerMemberName] string name = null) =>
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));

  private bool busy;
  public bool IsBusy {
    get { return busy; }
    set {
      busy = value;
      OnPropertyChanged();
      //Update the can execute
      GetCartoonCharactersCommand.ChangeCanExecute();
    }
  }

  private async Task GetCartoonCharacters() {
    if (IsBusy)
        return;

    Exception error = null;
    try {
      IsBusy = true;

      using (var client = new HttpClient()) {
        //grab json from server
        var json = await client.GetStringAsync(BASE_URL + "api/cartoon");

        //Deserialize json
        var items = JsonConvert.DeserializeObject<List<CartoonCharacter>>(json);

        //Load speakers into list
        CartoonCharacters.Clear();
        foreach (var item in items) {
          CartoonCharacters.Add(new CartoonCharacter() {
            Name = item.Name,
            PictureUrl = BASE_URL + item.PictureUrl
          });
        }
      }
    } catch (Exception ex) {
      Debug.WriteLine("Error: " + ex);
      error = ex;
    } finally {
      IsBusy = false;
    }

    if (error != null)
      await Application.Current.MainPage.DisplayAlert("Error!", error.Message, "OK");
  }
}


Resolve any missing namespaces then compile your application to make sure you do not have any errors.

Adding UI to our application

We will need to add some UI to our portable project as follows:
  • Open MainPage.xaml and delete the <Label …> tag.
  • Put the following XAML markup between the opening and closing <ContentPage …> tags:
<StackLayout Spacing="0" Padding="20,20,0,0">
  <Button Text="Get Cartoon Characters"
    Style="{StaticResource buttonStyle}"
    Command="{Binding GetCartoonCharactersCommand}"/>
  <ActivityIndicator IsRunning="{Binding IsBusy}" IsVisible="{Binding IsBusy}"/>
  <ListView x:Name="ListViewCartoonCharacters"
       ItemsSource="{Binding CartoonCharacters}">
    <ListView.ItemTemplate>
      <DataTemplate>
        <TextCell Text="{Binding Name}"/>
      </DataTemplate>
    </ListView.ItemTemplate>
  </ListView>
</StackLayout>


The above XAML markup just adds a button and a list. When the button is clicked, our application will retrieve data from a remote Web API service, then it will populate the list.
The button is bound to a method called GetCartoonCharactersCommand, which is already defined in our CartoonViewModel class.
  • Our UI uses a button style named buttonStyle. Add the following markup to App.xaml between the opening and closing <Application.Resources> tags:
<ResourceDictionary>
  <Style x:Key="buttonStyle" TargetType="Button">
    <Setter Property="HorizontalOptions" Value="Center" />
    <Setter Property="VerticalOptions" Value="CenterAndExpand" />
    <Setter Property="BorderColor" Value="Black" />
    <Setter Property="BorderRadius" Value="3" />
    <Setter Property="BorderWidth" Value="3" />
    <Setter Property="WidthRequest" Value="200" />
    <Setter Property="TextColor" Value="Black" />
    <Setter Property="BackgroundColor" Value="Silver" />
  </Style>
</ResourceDictionary>

  • To bind our MainPage.xaml UI to the CartoonViewModel , add the following code to bottom of the MainPage() constructor in MainPage.xaml.cs, right under InitializeComponent();
//Create the view model and set as binding context
CartoonViewModel vm = new CartoonViewModel();
BindingContext = vm;

  • Let’s test out the application. Build and run it. You should see a window that looks like this:
image
  • Click on the “Get Cartoon Characters” button. It will retrieve the names of cartoon characters on the server:
image

Adding a details page

To enhance our application, we will build the feature so that when a user click on a particular cartoon character, it displays an image of that character in a separate page. It addition, it will allow the user to go to a webpage that displays the image.
  • We need to add an event handled in MainPage.xaml.cs that handles the item selection process. Add the following code to the bottom of the MagePage() constructor in MainPage.xaml.cs:
ListViewCartoonCharacters.ItemSelected += ListViewCartoonCharacters_ItemSelected;
  • Next, add the code for handling the event by adding this method to the MainPage class in MainPage.xaml.cs:
private async void ListViewCartoonCharacters_ItemSelected(object sender, SelectedItemChangedEventArgs e) {
  var character = e.SelectedItem as CartoonCharacter;
  if (character == null)
      return;

  await Navigation.PushModalAsync(new DetailsPage(character));
  ListViewCartoonCharacters.SelectedItem = null;
}


Note that an object is being passed in the constructor of a page DetailsPage, which we are about to create.
  • To the ComicMobile project, add a “Forms Xaml Page” and name it DetailsPage.xaml.
image
  • In DetialsPage.xaml, replace the <Label …> tag with the following XAML markup:
<ScrollView Padding="10">
  <StackLayout Spacing="10" >
    <!-- Detail controls here -->
    <Image Source="{Binding PictureUrl}" HeightRequest="200" WidthRequest="200"/>

    <Label Text="{Binding Name}" FontSize="24" HorizontalTextAlignment="Center"/>
    <Button Text="Show image on Website" x:Name="ButtonWebsite" Style="{StaticResource buttonStyle}"/>
  </StackLayout>
</ScrollView>

  • Add the following instance variable to the DetailsPage class in DetailsPage.xaml.cs:
CartoonCharacter _cartoonCharacter;
  • Replace the DetailsPage() constructor with the following code that takes a CartoonCharacter as an argument:
public DetailsPage(CartoonCharacter cartoonCharacter) {
  InitializeComponent();

  //Set local instance of speaker and set BindingContext
  this._cartoonCharacter = cartoonCharacter;
  BindingContext = this._cartoonCharacter;

  ButtonWebsite.Clicked += ButtonWebsite_Clicked;
}

  • Add the following event handler method to the DetailsPage class to handle the button click for viewing a webpage:
private void ButtonWebsite_Clicked(object sender, EventArgs e) {
  if (_cartoonCharacter.PictureUrl.StartsWith("http"))
    Device.OpenUri(new Uri(_cartoonCharacter.PictureUrl));
}

  • Build and run your application.
image
  • Click on the “Get Cartoon Characters” button.
image
  • Click on a name like “Donald Duck”.
image
  • Click on the “Show image on Website” button. It will open a web page in your browser that just displays the image:
image

Android

Try running this same application in the Visualk Studio 2015 Android emulator by making the Android project (ComicMobile.Droid) your startup application.

image
image
image

a single code base, we were able to develop an app that runs on Android, iOS, and Windows. This is the power of Xamarin Forms.

Consuming a Swagger service in Visual Studio 2015

In a previous post I discuss how to add Swagger to an ASP.NET Core 1.0 application. In this post I will show you how to use it.

We will build a simple C# command-line console application to consume a Swagger service at http://cartoonapi.azurewebsites.net/api/cartoon. This service displays a list of cartoon characters and a link of their images. Point your browser to the above address and you will see this output:

[{"name":"Aladdin","pictureUrl":"images/aladdin.png"},
{"name":"Bambam Rubble","pictureUrl":"images/bambam_rubble.png"},
{"name":"Bambi","pictureUrl":"images/bambi.png"},
{"name":"Barney Rubble","pictureUrl":"images/barney_rubble.png"},
{"name":"Betty Flintstone","pictureUrl":"images/betty_flintstone.png"},
{"name":"Dino","pictureUrl":"images/dino.png"},
{"name":"Donald Duck","pictureUrl":"images/donald_duck.png"},
{"name":"Flintstone Family","pictureUrl":"images/flintstone_family.png"},
{"name":"Flounder","pictureUrl":"images/Flounder.png"},
{"name":"Fred Flintstone","pictureUrl":"images/fred_flinrstone.png"},
{"name":"Goofy","pictureUrl":"images/Goofy.png"},
{"name":"Jasmine","pictureUrl":"images/jasmine.png"},
{"name":"Jumbo","pictureUrl":"images/jumbo.png"},
{"name":"Mermaid","pictureUrl":"images/mermaid.png"},
{"name":"Micky Mouse","pictureUrl":"images/micky_mouse.png"},
{"name":"Minnie Mouse","pictureUrl":"images/minnie_mouse.png"},
{"name":"Pebbles Flintstone","pictureUrl":"images/pebbles_flintstone.png"},
{"name":"Peter Pan","pictureUrl":"images/peter_pan.png"},
{"name":"Pinocchio","pictureUrl":"images/pinocchio.png"},
{"name":"Pluto","pictureUrl":"images/pluto.png"},
{"name":"Simba","pictureUrl":"images/simba.png"},
{"name":"Snow White","pictureUrl":"images/snow_white.png"},
{"name":"Tigger","pictureUrl":"images/tigger.png"},
{"name":"Tinkerbell","pictureUrl":"images/tinkerbell.png"},
{"name":"Tweety","pictureUrl":"images/tweety.png"},
{"name":"Wilma Flintstone","pictureUrl":"images/wilma_flintstone.png"},
{"name":"Winnie The Pooh","pictureUrl":"images/winnie_the_pooh.png"}]


Note that there are two properties in the above object representing a cartoon character – name & pictureUrl.
The Swagger documentation is located at http://cartoonapi.azurewebsites.net/swagger/ui/. This URL displays the following page:

image

The swagger.json file contains the description of the serice and will be used later to create a C# client.

Creating a blank C# Console App

Let us start by creating our console application.
  • Start Visual Studio 2015
  • File >> New >> Project
  • Templates >> Visual C# >> Windows >> Console Application
  • Name the application MySwaggerClient

Adding Swagger client code to our console app

Point your browser to the address of your Swagger service. If you wish to go along with this example, access this page in your browser:

http://cartoonapi.azurewebsites.net/swagger/v1/swagger.json.

Copy all the contents of the JSON object on the page into the clipboard by hitting CTRL + A followed by CTRL + C on your keyboard.

Back in Visual Studio 2015, add a text file to your project and name it swagger.json. Paste the contents of your clipboard into swagger.json then save the file. You will notice that Visual Studio formats this file properly and it is possible to make sense of the content. Close inspection of the file reveals that this JSON file is a description of the remote service and it is intended for use by IDEs and code generators. We will next have Visual Studio 2015 interpret this description file and subsequently generate C# client code for us.

Right-click on the project node >> Add >> REST API Client…

image

image

Click on the second “Select an existing metadata file” radio button, then browse to the swagger.json file and select it. Click on OK when you are done.

Visual Studio 2015 will then generate client code for your project. You should see additional C# files added to your project as shown below:

image

Note two model classes: CartoonCharacter.cs and CartoonCharacterCollection.cs. These represent the model classes on the server.

Build your app to make sure that you do not have any errors.

Using the Swagger client code in our application

Since we will be making a remote call, it is best that we access the service asynchronously. Therefore we will use all the asynchronous versions of the calling methods.

Add the following async method to Program.cs:

static async Task<IEnumerable<CartoonCharacter>> GetAsync() {
  string baseUrl = "
http://cartoonapi.azurewebsites.net/";
  using (var client = new Auth0SwaggerSampleAPI(new Uri(baseUrl))) {
    var results = await client.ApiCartoonGetAsync();
    IEnumerable<CartoonCharacter> comic = results.Select(m => new CartoonCharacter
    {
      Name = m.Name,
      PictureUrl = m.PictureUrl
    });
    return comic;
  }
}


We first assign the base URL of our remote service to a variable named baseUrl. We then instantiate an instance of Auth0SwaggerSampleAPI. This is essentially the name of the class that Visual Studio created for us and represents the remote service. The instance of the Auth0SwaggerSampleAPI class is represented by the client object. With the client object we can call a method ApiCartoonGetAsync(), which returns all items into a variable results. Using a LINQ Lambda Expression, we can then populate a list of CartoonCharacter objects. We then return the list.

Add another async method that displays the contents of the collection to a terminal window:

static async Task RunAsync() {
  IEnumerable<CartoonCharacter> comic = await GetAsync();

  foreach (var item in comic) {
    Console.WriteLine("{0}, {1}",item.Name, item.PictureUrl);
  }
}


Lastly, we will add a method call to RunAsync() from within the Main() method that runs asynchronously. Add the following to the Main() method.

RunAsync().Wait();

If you now build and run your console application, you should see the following output:

Barney Rubble, images/barney_rubble.png
Betty Flintstone, images/betty_flintstone.png
Dino, images/dino.png
Donald Duck, images/donald_duck.png
Flintstone Family, images/flintstone_family.png
Flounder, images/Flounder.png
Fred Flinrstone, images/fred_flinrstone.png
Goofy, images/Goofy.png
Jasmine, images/jasmine.png
Jumbo, images/jumbo.png
Mermaid, images/mermaid.png
Micky Mouse, images/micky_mouse.png
Minnie Mouse, images/minnie_mouse.png
Pebbles Flintstone, images/pebbles_flintstone.png
Peter Pan, images/peter_pan.png
Pinocchio, images/pinocchio.png
Pluto, images/pluto.png
Simba, images/simba.png
Snow White, images/snow_white.png
Tigger, images/tigger.png
Tinkerbell, images/tinkerbell.png
Tweety, images/tweety.png
Wilma Flintstone, images/wilma_flintstone.png
Winnie The Pooh, images/winnie_the_pooh.png


Lesson leaned – Visual Studio 2015 offers a very easy way to consume a Swagger service that can be used in a variety of your applications.


Reference:

https://azure.microsoft.com/en-us/documentation/articles/app-service-api-dotnet-get-started/

Wednesday, November 2, 2016

Adding Swagger to ASP.NET Core 1.0 Web API app

Swagger is an API specification framework. It reminds me of WSDL in the SOAP days. In this article I will guide you in add Swagger documentation to an ASP.NET Core Web API app.

There are two components that we need to buckle-up in our Web API application. These are, not surprisingly, called Swashbuckle:
  1. Swashbuckle.SwaggerGen : provides functionality to generate JSON Swagger documents that describe the objects, methods, return types, etc.
  2. Swashbuckle.SwaggerUI : embedded version of Swagger UI tool which uses the above documents for a rich customizable experience for describing the Web API functionality and includes built in test harness capabilities for the public methods.
For starters, add the following package to your project.json:

"Swashbuckle": "6.0.0-beta902"

Next, add the SWaggerGen library to your middle-ware by adding the following line of code to the bottom of the ConfigureServices() method in Startup.cs:

services.AddSwaggerGen();

Also, add the following two lines of code to the bottom of the Cofigure() method in Startup.cs:

// Enable middleware to serve generated Swagger as a JSON endpoint
app.UseSwagger();

// Enable middleware to serve swagger-ui assets (HTML, JS, CSS etc.)
app.UseSwaggerUi();


Point your browser to http://localhost:{port number}/swagger/v1/swagger.json and you will see a JSON document that describes the endpoints of your service.

image

You can also see the Swagger UI at URL http://localhost{port number}/swagger/ui.

image

In the above example the API service is Studentapi. Your service will be under API V1. Click on it and you will see something similar to the following:

image

To test out GET, click on the first blue GET button and the section will expand describing to you the structure of your object:

image

Click on the “Try it out!” button to view the data coming back from the service for all items in the collection:

image

Click on the first blue GET button again to collapse the section. Now, click on the second blue GET button to test retrieval of an item by id.

image

Enter a value for ‘id’ then click the “Try it out!” button. It should get for you the item for that id.

image

In a similar manner, go ahead and test out all the other POST, DELETE, and PUT buttons.

The official Swagger website at http://swagger.io/. You can generate a Swagger client for most programming languages at http://editor.swagger.io/.