Angular Intro
Today we'll take a good look at Angular. Angular is a TypeScript-based open-source web application framework led by the Angular Team at Google and by a community of individuals and corporations. Angular is a complete rewrite from the same team that built AngularJS.
Angular.js i.e less than or below version 2.0 is based on MVC Architecture and the angulr i.e from version 2.0 is based on Component Service based architecture.
Specifically, we'll explore how the following aspects work :
- Getting started
- Building the UI
- Passing data between components
- Handling forms
- Routing
- Fetching data from an API
- Pros and cons
Angular is a JavaScript framework which enables you to run client web applications in the browser, but also create native (mobile) and desktop apps.
Broadly speaking, your Angular app will consist of lots of components, written using JavaScript (or TypeScript) and decorated with something Angular refers to as “directives” to handle things like binding your markup (HTML) to data.
The code you write with Angular cannot run directly in the browser, so you need a compiler to transform your code into something the browser can run.
Since Angular 9, the default option is to use the "Ahead-of-time compiler" to transform your code into efficient JavaScript as part of a build/publish process. The browser can then download and run this compiled JavaScript code.
Alternatively, you can use the "Just-in-time compiler" to compile your app in the browser at runtime.
When a user accesses your Angular application, the browser's JavaScript engine kicks in to execute your application's code.
Creating a New Angular App
Angular has its own CLI for creating projects and generating application code.
You can install it using Yarn or npm.
npm install -g @angular/cli
Spinning up a new app is a case of running this command.
ng new my-app
The CLI gives you a few options at this point, specifically asking whether you want to include Angular Routing and which stylesheet format you want (CSS, SCSS etc.).
Angular CLI add component questions
Then you can run your app using this command.
ng serve
For more details visit: https://angular.io
Building Your UI with Angular
Angular adopts a component approach to building your UI.
For example, let's create a simple Hello World component which lets the user enter their name for a more personalized greeting.
You can use the Angular CLI to generate a new component.
ng generate HelloWorld
This gives you four files:
- hello-world.component.css
- hello-world.component.html
- hello-world.component.spec.ts
- hello-world.component.ts
By default Angular leans quite heavily on TypeScript, which then gets compiled to regular JavaScript to run in the browser.
We can build a simple Hello World UI...
hello-world.component.html
<label>What's your name?
<input (keyup)="onKey($event)" placeholder="name"/>
</label>
<span>Hello {{name}}</span>
This is a mix of standard HTML and Angular syntax to handle DOM events and display data.
(keyup)="onKey($event)" directs Angular to invoke an onKey function every time the user types something into the text input.
{{name}} uses Angular's interpolation syntax {{ }} to render the current value of a name field, which is declared in the corresponding hello-world.component.ts file.
hello-world.component.ts
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-hello-world',
templateUrl: './hello-world.component.html',
styleUrls: ['./hello-world.component.css']
})
export class HelloWorldComponent implements OnInit {
name = '';
ngOnInit(): void {
}
onKey(event: any) {
this.name = event.target.value;
}
}
You can see there's a bit of boilerplate code here.
We have the @Component declaration which tells Angular how we'll reference this component from other components (the selector), where its UI markup (HTML) and styles (CSS) live.
Then follows a TypeScript class called HelloWorldComponent which houses our main component logic.
This class implements OnInit from the Angular core library which, in turn, requires us to implement an ngOnInit method in our class.
Finally, we have the name field we're using to store the entered name, and the onKey function that will be invoked as our users type something into the text input.
To view this component, we need to render it somewhere in our application, which we can do using the selector we defined earlier.
<h1>A brief introduction to Angular</h1>
<app-hello-world></app-hello-world>
With all that in place (and sticking to Angular's "out of the box" default styles) we get a functional, if slightly bland looking, personalized greeting!
In summary, an Angular UI:
- Comprises one or more components
- Is typically written using TypeScript or JavaScript and special Angular directives
- Runs on the browser's JavaScript engine
Passing Data Around
We've already seen one way to handle state in Angular components, by storing it in a field (as with name in our Hello world example).
But another common approach is to pass values into a component.
For example, you might choose to pass in a custom headline when you declare an instance of our Hello World component...
<app-hello-world headline="Welcome, it's great to see you"></app-hello-world>
This enables us to use this same component in different places, but with different headlines for each one.
Angular makes this possible using something called Input.
We can modify our component to accept a headline by adding an @Input to the existing HelloWorldComponent class.
export class HelloWorldComponent implements OnInit {
@Input() headline: string;
// existing code
}
We can now pass a value or headline into our component, but it isn't rendered anywhere yet. To solve that, we can use Angular's interpolation syntax {{ }} to show the value of headline wherever we want...
hello-world.component.html
<h2>{{headline}}</h2>
<label>What's your name?
<input (keyup)="onKey($event)" placeholder="name"/>
</label>
<span>Hello {{name}}</span>
Now when we run this in the browser, we'll see the custom headline.
Handling Forms
Handling keyup and similar events works fine to a point, but there are some limitations.
For example, in our HelloWorld component, if you change the value of name programmatically in the HelloWorldComponent class, this won't be reflected in the text input.
For this two-way binding requirement we need a different approach.
Enter the humble HTML form!
Angular has two primary options for handling forms:
Reactive Forms
Template Driven Forms
Arguably, Reactive Forms what we'll focus on here.
Here's the markup for a "contact us" Reactive Form by way of example.
<section>
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<label>
Name:
<input type="text" formControlName="name" required>
</label>
<label>
Thoughts?:
<input type="text" formControlName="comments">
</label>
<div *ngIf="name.invalid && name.errors.required && !name.pristine">
Name is required.
</div>
<input type="submit" value="Submit"/>
</form>
</section>
There's a bit to unpack here.
We've declared a FormGroup which points to a corresponding form field in our component's TypeScript.
Form Groups in Angular manage the values and validity status of fields in a form.
Each individual form control (in this case, each text input field) points to its own FormControl, which manages its own value and validity status.
We've used (ngSubmit) to point this form to an onSubmit() function which will be invoked when the form is submitted.
The TypeScript code for this form looks like this:
import {Component} from '@angular/core';
import {FormBuilder, FormGroup, Validators} from "@angular/forms";
@Component({
selector: 'app-contact-us',
templateUrl: './contact-us.component.html',
styleUrls: ['./contact-us.component.css']
})
export class ContactReactiveComponent {
form: FormGroup;
constructor() {
this.form = new FormGroup({
name: new FormControl('', [Validators.required]),
comments: new FormControl('')
})
}
onSubmit() {
console.log(`${this.form.value.name}:${this.form.value.comments}`);
}
get name() { return this.form.get('name') };
}
Besides the regular Angular component boilerplate, we have our form group (form).
In the constructor we've created and assigned a new form group to our form field, and declared our individual form controls for name and comments.
constructor() {
this.form = new FormGroup({
name: new FormControl('', [Validators.required]),
comments: new FormControl('')
})
}
We've flagged name as a required field using Validators.required.
onSubmit will log the form's values to the console when the form is submitted.
We also needed a way to access name from our component markup (to conditionally show or hide the validation errors) and that's handled by this line:
get name() { return this.form.get('name') };
Routing in Angular
In most applications you'll want to be able to handle routes.
So, for example, if someone accesses "/about" they might see your about "page" (which will actually render one or more components).
Angular handles routes via @angular/router and by default it looks for routes defined in an array in app-routing.module.ts.
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import {HelloWorldComponent} from "./hello-world/hello-world.component";
const routes: Routes = [
{ path: 'greetMe', component: HelloWorldComponent}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
In this example, any request to /greetMe will now attempt to render our HelloWorldComponent.
But this still won't show up anywhere until we give Angular a bit more direction.
Specifically, we need to include a router outlet in our application's main template, something like this in app.component.html:
<router-outlet></router-outlet>
With that in place, navigating to /greetMe will result in the HelloWorldComponent being displayed in place of our router-outlet element.
Fetching Data from an API
Angular advocates using services to fetch or save data in your components.
The concept is that the component itself should be unaware of the specific details of how data is fetched or saved.
You can generate a service using the Angular CLI:
ng generate service ticket
Here's an example service for fetching a list of support tickets.
ticket.service.ts
import {Injectable} from '@angular/core';
import {HttpClient} from "@angular/common/http";
import {Observable} from "rxjs";
@Injectable({
providedIn: 'root'
})
export class TicketService {
constructor(private http: HttpClient) {
}
getTickets(): Observable<Ticket[]> {
return this.http.get<Ticket[]>('api/Tickets');
}
}
class Ticket {
id: number;
name: string;
summary: string;
}
This leans on Angular's dependency injection to bring in an instance of HttpClient.
We can then make the HTTP call, mapping the response to an Observable array of tickets.
Now we can use getTickets in our component.
ticket-list.component.ts
export class TicketListComponent implements OnInit {
tickets:Ticket[];
constructor(private ticketService: TicketService) { }
ngOnInit(): void {
this.ticketService.getTickets()
.subscribe(tickets => this.tickets = tickets);
}
}
We inject an instance of TicketService, subscribe to its getTickets observable and assign the resulting array to the tickets field.
Finally, we can loop over this array in our component's template, using *ngFor.
<div *ngFor="let ticket of tickets">
{{ticket.name}}
</div>
Pros
- Well-established framework
- Everything you need is included
- TypeScript support is baked in and offers reliable type safety
- You can build Angular apps for web, native desktop and native mobile
Cons
- TypeScript brings its own learning curve
- Whether you use TypeScript or not, you're essentially required to write your components using JavaScript (either a pro or a con depending on your feelings toward JavaScript!)
- Angular itself carries a steep learning curve
- Angular's docs, while comprehensive, are jam-packed with Angular-specific terminology and concepts which can be hard to digest and fully understand on first read
In the above article the code snippets in the blue color.

Comments
Post a Comment