Introduction to Angular

What is Angular

Angular is a JavaScript-based front-end web application framework, maintained by google, that aims to change the way single-page applications are developed through component-based coding.

Angular !== Angularjs

Angular is not a newly released version of Angularjs, it’s a complete rewrite. There are tons of new features, and some old things that have been moved over to Angular.

While some of the functionality did move over, the syntax did not. Angular has made the syntax easier to use, and more logical for the writer.

Keys to Angular

TypeScript

Typescript is strongly typed superset of JavaScript that compiles into plain JavaScript. It starts from the same syntax that JavaScript developers know, but adds helpful features that make coding easier, such as type checking and object oriented features. For more information about typescript take a look at the Typescript handbook

JavaScript

var Todo = (function () {
	function Todo(todoId, todoText) {
		this.todoId = todoId;
		this.todoText = todoText;
	}
	Todo.prototype.getTodoId = function () {
		return (this.todoId);
	};
	Todo.prototype.setTodoId = function (newTodoId) {
		this.todoId = newTodoId;
	};
	Todo.prototype.getTodoText = function () {
		return (this.todoText);
	};
	Todo.prototype.setTodoText = function (newTodoText) {
		this.todoText = newTodoText;
	};
	return Todo;
}());

TypeScript

class Todo {
	constructor(private todoId: number, private todoText: string) {}

	getTodoId() : number {
		return(this.todoId);
	}

	setTodoId(newTodoId: number) {
		this.todoId = newTodoId;
	}

	getTodoText() : string {
		return(this.todoText);
	}

	setTodoText(newTodoText: string) {
		this.todoText = newTodoText;
	}
}

Important Design Patterns

Observables

Observables are used extensively in Angular, and are very similar to Promises but with some key differences. Observables and Promises are both used to perform the very important web application operation of posting and getting data from a server.

In Angular, Observables are used for triggering events and obtaining new data. The reason Observables won out over Promises in Angular 2 is because it provides more features than Promises, and is much more flexible.

For example, it doesn’t matter if you want to handle a 0, 1, or multiple events - an Observable can use the same API for each case. A Promise will only return a single value.

Dependency Injection

Dependency Injection is a design pattern where an object can inject dependencies into another object. Dependency injection is used extensively in Angular to share data and behavior across different components.

Decorator Pattern

Decorators allows objects to be altered with out affecting their structure. This allows Objects to gain functionality without unintended side effects. In Angular Decorators are specified with a@sign and provides options to customize classes/objects depending on the use case.

Angular Architecture

Components

In Angularjs, to build and specify elements, you had to use directives, controllers, and scope. Angular simplified this and made it all achievable through a component and a view. Components handles all the business logic for the view. Components require the @Component decorator

/src/app/splash/splash.component.ts
import {Component, OnInit} from "@angular/core";
import {User} from "../shared/interfaces/user";
import {ApiService} from "../shared/services/api.service";
import {Router} from "@angular/router";

@Component({
	templateUrl: "./splash.component.html"
})


export class SplashComponent implements OnInit{
	users: User[] = [];

	constructor(protected userService: ApiService, private router: Router) {}


	ngOnInit():void {
		this.userService.getAllUsers()
			.subscribe(users => this.users = users);
	}

	getDetailedView(user : User) : void {
		this.router.navigate(["/detailed-user/", user.userId]);
	}

}

Templates in Angular


Templates provide the presentation or view for components. Basically, a template is what we use to help render HTML with dynamic parts. Templates give us the ability to express data through the binding of properties, and events. To do this, Angular 2 comes with some key symbols the author can use to express certain behaviors:


  • {{ }} for Interpolation.
  • [ ] for Property Binding.
  • ( ) for Event Binding.
  • # for Variable Declaration.
  • * for Structural Directives.

Data Binding

Data binding is Angular’s way of synchronizing data between the model and the view.

In Angular, there are multiple ways to bind data: interpolation, one way binding (unidirectional), two-way binding, and event binding. Interpolation is the easiest and best-known way. The biggest reason for this is to keep the front and backend synced.

/src/app/splash/splash.template.ts
<main class="container">
	<table class="table table-bordered table-responsive">
		<tr>
			<th>User Id</th>
			<th>Name</th>
			<th>Email</th>
			<th>Phone</th>
			<th>Username</th>
			<th>Website</th>
		</tr>
		<tr (click)="getDetailedView(user)" *ngFor="let user of users">
			<td>{{user.userId}}</td>
			<td>{{user.name}}</td>
			<td><a [href]="'mailto:' + user.email">{{user.email}}</a></td>
			<td>{{user.phone}}</td>
			<td>{{user.username}}</td>
			<td>{{user.website}}</td>
		</tr>
	</table>
	<!--https://stackoverflow.com/questions/45749533/what-is-input-used-for-->
</main>
Disclaimer: there should be no spaces between the curly brackets

Services

Through the use of Dependency Injection service objects can be shared through any number of components. Because of this services are ideal for managing state, bring data into applications or to do repetitive tasks. In order to use Dependency injection Service classes must invoke the @Injectable() decorator.

/src/app/shared/services/api.services.ts
import {Injectable} from "@angular/core";

import {Status} from "../interfaces/status";
import {User} from "../interfaces/user";
import {UserPosts} from "../interfaces/userPosts";

import {Observable} from "rxjs/internal/Observable";
import {HttpClient} from "@angular/common/http";

@Injectable ()
export class ApiService {

	constructor(protected http : HttpClient ) {}

	//define the API endpoint
	private apiUrl = "https://bootcamp-coders.cnm.edu/~gkephart/ng-demo7-backend/public_html/api/";


	// call to the tweet API and create the tweet in question
	createUser(user : User) : Observable<Status> {
		return(this.http.post<Status>(this.apiUrl, user));
	}

	// call to the tweet API and get a tweet object based on its Id
	getUser(userId : string) : Observable<User> {
		return(this.http.get<User>(this.apiUrl + userId));

	}

	// call to the API and get an array of tweets based off the profileId
	getDetailedUser(userId : string) : Observable<UserPosts[]> {
		return(this.http.get<UserPosts[]>(this.apiUrl + "?postUserId=" + userId ));

	}

	//call to the API and get an array of all the tweets in the database
	getAllUsers() : Observable<User> {
		return(this.http.get<User>(this.apiUrl));

	}




}

HTTP Interceptor

Http Interceptors are a new feature in Angular that was introduced in Angular 4.3. Interceptors are powerful tools that mutate or change incoming and outgoing HTTP calls. Interceptors accomplish this by sitting between the service and HTTP and modify the stream that observables (in the services) interact with.

/src/app/interceptors/deepdive.interceptor.ts
import {Injectable} from "@angular/core";
import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse} from "@angular/common/http";
import {Observable} from "rxjs/Observable";

/**
 * class that intercepts data for Deep Dive's API standard
 *
 * All APIs in Deep Dive return an object with three state variables:
 *
 * 1. status (int, required): 200 if successful, any other integer if not
 * 2. data (any, optional): result of a GET request
 * 3. message (string, optional): status message result of a non GET request
 *
 * this interceptor will use the HttpResponse to return either the data or the status message
 **/
@Injectable()
export class DeepDiveInterceptor implements HttpInterceptor {

	/**
	 * intercept method that extracts the data or status message based on standards outlined above
	 *
	 * @param {HttpRequest<any>} request incoming HTTP request
	 * @param {HttpHandler} next outgoing handler for next interceptor
	 * @returns {Observable<HttpEvent<any>>} Observable for next interceptor to subscribe to
	 **/
	intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
		// hand off to the next interceptor
		return(next.handle(request).map((event: HttpEvent<any>) => {
			// if this is an HTTP Response, from Angular...
			if(event instanceof HttpResponse) {
				// create an event to return (by default, return the same event)
				let dataEvent = event;

				// if the API is successful...
				if(event.status === 200) {

					// extract the data or message from the response body
					let body = event.body;
					if(body.status === 200) {
						if(body.data) {
							// extract data returned from a GET request
							dataEvent = event.clone({body: body.data});
						} else if(body.message) {
							// extract a successful message
							dataEvent = event.clone({body: {message: body.message, status: 200, type: "alert-success"}});
						}
					} else {
						// extract a failing message when the API fails
						dataEvent = event.clone({body: {message: body.message, status: body.status, type: "alert-danger"}});
					}
				} else {
					// extract a failing message when the web server fails
					dataEvent = event.clone({body: {message: event.statusText, status: event.status, type: "alert-danger"}});
				}
				return(dataEvent);
			}
		}));
	}
}

Modularity

/src/app/app.module is the central piece of an angular app. A module is a self contained chunk of code that can function by its self or plugged into other code. Angular Modules are denoted with the @ngModule decorator that takes an object as an argument with four variables whose values must be arrays. Those variables are: imports, declarations, bootstrap, and providers.

  • imports: Defines what outside modules should be brought in the project. These Modules can be official Angular modules like ReactiveFormsModule, third party plugins downloaded through NPM like @auth0/angular-jwt or modules defined in the project.
  • declarations: Specifies what components can be used in the Application/Module.
  • providers: Specifies what services or other providers like interceptors can use Dependency Injection in the Application/Module.
  • bootstrap: Declares the root component that will be injected into the base index.html.
import { NgModule,  } from '@angular/core';
import {HttpClientModule} from "@angular/common/http";
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import {ReactiveFormsModule} from "@angular/forms";
import {allAppComponents, providers, routing} from "./app.routes"
import { AppComponent } from './app.component';
import { HelloComponent } from './hello.component';

@NgModule({
	imports:      [ BrowserModule, FormsModule, HttpClientModule, routing, ReactiveFormsModule],
	declarations: [ ...allAppComponents, AppComponent],
	bootstrap:    [ AppComponent ],
	providers:    [providers]
})
export class AppModule { }

Routes

/src/app/app.routes.ts defines the navigable pages in the application. Routing can be defined in app.module.ts it is best practice to define routes in a separate module on the same level as app.module.ts

  • export const routes: Routes is an array of route objects. the route object defines the url path to page and what component should be called when the page is visited.
  • export const allAppComponents: Consists of an array of component objects that are exported to /src/app/app.module.ts and declared int the declarations field.
  • export const providers: Consists of an array of service objects and other provider objects that are exported to /src/app/app.routes.ts and is declared in the providers field.
import {RouterModule, Routes} from "@angular/router";
import {SplashComponent} from "./splash/splash.component";
import {UserDetailComponent} from "./user-detail/user-detail.component";
import{AppComponent} from "./app.component"

import {HTTP_INTERCEPTORS} from "@angular/common/http";
import {DeepDiveInterceptor} from "./shared/interceptors/deep-dive.interceptor";
import {ApiService} from "./shared/services/api.service";

import {APP_BASE_HREF} from "@angular/common";

export const routes: Routes = [
	{path: "", component: SplashComponent},
	{path: "detailed-user/:userId", component: UserDetailComponent}
];

export const allAppComponents = [AppComponent, SplashComponent, UserDetailComponent]


export const providers: any[] =[
	ApiService,
	{provide: HTTP_INTERCEPTORS, useClass: DeepDiveInterceptor, multi: true}

];

export const routing = RouterModule.forRoot(routes);

Live Example