Angular
Angular
1
Angular
Angular is a development platform, built on TypeScript. As a platform, Angular includes:
With Angular, you're taking advantage of a platform that can scale from single-developer projects to enterprise-level
applications. Angular is designed to make updating as straightforward as possible, so take advantage of the latest
developments with minimal effort. Best of all, the Angular ecosystem consists of a diverse group of over 1.7 million developers,
library authors, and content creators.
According to the 2022 StackOverflow survey, 23 percent of software engineers apply the framework to create user interfaces.
2
History of Angular
Its history traces back to 2009 when Misko Hevery and Adam Abrons, Google engineers, developed the framework known as
AngularJS and officially released it in 2010.
AngularJS revolutionized web development by providing a convenient way to build dynamic, single-page applications (SPAs).
Designing complex dynamic web pages with pure or vanilla JavaScript is time-consuming. Not to mention that, in big projects
involving many programmers, the front-end is a challenge to understand and maintain. So, the key idea behind AngularJS was
to simplify SPA development by introducing several considerable advantages.
MVC architecture: AngularJS divides your web app into three distinct parts — Model (data), View (the UI layer), and Controller
(business logic). The three units can be developed in parallel and separately tested. As a result, the code becomes easier to
understand, maintain, and extend.
Two-way data binding: The JavaScript framework synchronizes the Model and the View by applying a two-way data binding
technique. As the data in the Model changes, the View does too. This allows engineers to reduce development time as it
doesn’t require writing additional code to provide continual View and Model synchronization.
3
History of Angular
Dependency injection (DI): AngularJS comes with a built-in mechanism to pass (inject) dependencies — or rules defining how
pieces of code interact with each other and behave under certain conditions — instead of creating them inside the
components. This enables developers to change or configure dependencies without altering an app module as well as reuse
them across multiple modules. All in all, DI simplifies testing and contributes to the reusability and maintainability of app
components.
Featuring a prominent set of benefits, AngularJS quickly grew in popularity. But unfortunately for the framework, technologies
developed even faster. Before long, the platform stopped meeting the rising requirements of the web and lost its position to
newer competitors. So, in 2014, Google decided to completely rewrite it.
For several years, AngularJS has existed side by side with its successor simply named Angular. But in 2022, it, at last, reaches the
end of life, i.e., the community will no longer maintain the framework. That said, devoted users can still find support from third
parties, and AngularJS code will remain on GitHub.
4
AngularJS vs Angular
In September 2016, Google released Angular 2. The difference between the old AngularJS and the new version was so radical
that you couldn’t just update from one to the other. The main changes are as follows.
TypeScript instead of JavaScript: Unlike its JS-based predecessor, Angular uses TypeScript.
Better performance: Both AngularJS and Angular significantly reduce development time. However, due to the component-
based architecture and more effective data binding, Angular apps can be five times faster than AngularJS.
Introducing CLI AngularJS doesn’t have its own command line interface (CLI). Angular 2+, on the other hand, comes with a CLI
that allows for quick generation of components, services, directives, etc.
Mobile-friendliness AngularJS was not designed with mobile browsers in mind. When developing Angular, Google took into
account this gap so the new framework got the support for mobile web and native mobile apps.
5
Setting up the development environment
You can use the Angular CLI to create projects, generate application and library code, and perform a variety of ongoing
development tasks such as testing, bundling, and deployment.
To install the Angular CLI, open a terminal window and run the following command: npm install -g @angular/cli
Run the CLI command ng new and provide the name my-app: ng new my-app
The ng new command prompts you for information about features to include in the initial app. Accept the defaults by
pressing the Enter or Return key.
The Angular CLI includes a server, for you to build and serve your app locally.
cd my-app
ng serve --open
6
The ng serve command launches the server, watches your files, and rebuilds the app as you make changes to those files.
The --open (or just -o ) option automatically opens your browser to http://localhost:4200/.
If the installation and setup was successful, you should see a page similar to the following.
App
7
Project Architecture
.vscode: Includes VS Code configuration files
node_modules: Includes npm packages needed for development and running the Angular application
.gitignore: Specifies files and folders that Git should not track
package.json and package-lock.json: Provide definitions of npm packages, along with their exact versions, which are
needed to develop, test, and run the Angular application
README.md: A README file that is automatically generated from the Angular CLI
app: Contains all the Angular-related files of the application. You interact with this folder most of the time during
development.
favicon.ico: The icon displayed in the tab of your browser, along with the page title.
styles.css: Contains application-wide styles. These are CSS styles that apply globally to the Angular application. The
extension of this file depends on the stylesheet format you choose when creating the application
9
Project Architecture
The app folder contains the actual source code we write for our application. Developers spend most of their time inside that
folder. The Angular application that is created automatically from the Angular CLI contains the following files:
10
Angular Essentials
Components
Managing dynamic data
Rendering dynamic templates
Conditional and loops
Handling User Interaction
Sharing logic
11
Components
Components provide structure for organizing your project into easy-to-understand parts with clear responsibilities so that your
code is maintainable and scalable.
Here is an example of how a Todo application could be broken down into a tree of components.
12
Defining a component
Every component has the following core properties:
// todo-list-item.component.ts
@Component({
standalone: true,
selector: 'todo-list-item',
template: ` <li>(TODO) Read Angular Essentials Guide</li> `,
styles: `li {
color: red;
font-weight: 300;
}`,
})
export class TodoListItem {
/* Component behavior is defined in here */
}
13
Separating HTML and CSS into separate files:
// todo-list-item.component.ts
@Component({
standalone: true,
selector: 'todo-list-item',
templateUrl: './todo-list-item.component.html',
styleUrl: './todo-list-item.component.css',
})
export class TodoListItem {
/* Component behavior is defined in here */
}
/* todo-list-item.component.css */
li {
color: red;
font-weight: 300;
}
14
Using a Component
One advantage of component architecture is that your application is modular. In other words, components can be used in
other components.
// todo-list.component.ts
import {TodoListItem} from './todo-list-item.component.ts';
@Component({
standalone: true,
imports: [TodoListItem],
template: `
<ul>
<todo-list-item></todo-list-item>
</ul>
`,
})
export class TodoList {}
15
Managing Dynamic Data
Define component state (i.e. component's data) and behavior to manage dynamic data.
To define state, you use class fields syntax inside of your component.
When you want to update state, this is typically accomplished by defining methods in the component class that can access the
various class fields with the this keyword.
// todo-list-item.component.ts
@Component({ ... })
export class TodoListItem {
taskTitle = '';
isComplete = false;
completeTask() {
this.isComplete = true;
}
updateTitle(newTitle: string) {
this.taskTitle = newTitle;
}
}
16
Rendering dynamic data
When you need to display dynamic content in your template, Angular uses the double curly brace syntax in order to distinguish
between static and dynamic content.
@Component({
selector: 'todo-list-item',
template: `
<p>Title: {{ taskTitle }}</p>
`,
})
export class TodoListItem {
taskTitle = 'Read cup of coffee';
}
This syntax declares an interpolation between the dynamic data property inside of the HTML. As a result, whenever the data
changes, Angular will automatically update the DOM reflecting the new value of the property.
17
Dynamic Properties
When you need to dynamically set the value of standard DOM properties on an HTML element, the property is wrapped in
square brackets to inform Angular that the declared value should be interpreted as a JavaScript-like statement (with some
Angular enhancements) instead of a plain string.
@Component({
selector: 'sign-up-form',
template: `
<button type="submit" [disabled]="formIsInvalid">Submit</button>
`,
})
export class SignUpForm {
formIsInvalid = true;
}
18
Dynamic Attributes
In the event you want to dynamically bind custom HTML attributes (e.g., aria-, data-, etc.), you might be inclined to wrap the
custom attributes with the same square brackets.
@Component({
standalone: true,
template: `
<button [attr.data-test-id]="testId">Primary CTA</button>
`,
})
export class AppBanner {
testId = 'main-cta';
}
19
Conditionals and Loops
We can create a feature module called orders
One of the advantages of using a framework like Angular is that it provides built-in solutions for common problems that
developers encounter. Examples of this include: displaying content based on a certain condition, rendering a list of items based
on application data, etc.
To solve this problem, Angular uses built-in control flow blocks, which tell the framework when and how your templates should
be rendered.
20
Conditional rendering
@if block
Similar to JavaScript's if statement, Angular uses @if control flow blocks to conditionally hide and show part of a template
and its contents.
@else block
While the @if block can be helpful in many situations, it's common to also show fallback UI when the condition is not met.
// user-controls.component.ts
@Component({
standalone: true,
selector: 'user-controls',
template: `@if (isAdmin) {
<button>Erase database</button>
} @else {
<p>You are not authorized.</p>
}`,
})
export class UserControls { isAdmin = true; } 21
Rendering a list
@for block
<!-- ingredient-list.component.html -->
<ul>
@for (ingredient of ingredientList; track ingredient.name) {
<li>{{ ingredient.quantity }} - {{ ingredient.name }}</li>
}
</ul>
track property
When Angular renders a list of elements with @for , those items can later change or move. Angular needs to track each
element through any reordering, usually by treating a property of the item as a unique identifier or key.
This ensures any updates to the list are reflected correctly in the UI and tracked properly within Angular, especially in the case
of stateful elements or animations.
To accomplish this, we can provide a unique key to Angular with the track keyword.
22
Event Handling
You can add an event handler to an element by:
// text-transformer.component.ts
@Component({
standalone: true,
selector: 'text-transformer',
template: `
<p>{{ announcement }}</p>
<button (click)="transformText()">Abracadabra!</button>
`,
})
export class TextTransformer {
announcement = 'Hello again Angular!';
transformText() {
this.announcement = this.announcement.toUpperCase();
}
}
23
Event Handling
Other common examples of event listeners include:
If you need to access the event object, Angular provides an implicit $event variable that you can pass to a function:
<button (click)="createUser($event)">Submit</button>
24
Sharing Code
When you need to share logic between components, Angular leverages the design pattern of dependency injection that allows
you to create a “service” which allows you to inject code into components while managing it from a single source of truth.
A TypeScript decorator that declares the class as an Angular service via @Injectable and allows you to define what part of
the application can access the service via the providedIn property (which is typically 'root' ) to allow a service to be
accessed anywhere within the application.
A TypeScript class that defines the desired code that will be accessible when the service is injected
25
import {Injectable} from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class CalculatorService {
add(x: number, y: number) {
return x + y;
}
}
26
Services
When you want to use a service in a component, you need to:
27
Two way binding
Angular, two-way data binding is typically used with form controls, allowing you to bind the value of an input field to a
property in your component.
Property Binding [property] : Binds a property of a DOM element to a property in your component.
Event Binding (event) : Listens for events emitted by a DOM element and triggers a method in your component.
By combining these two bindings with [(ngModel)] , you create a two-way binding, where changes in the input field
immediately update the component property, and changes to the component property immediately update the input field.
28
Two way binding
Developers commonly use two-way binding to keep component data in sync with a form control as a user interacts with the
control.
29
@Input & Custom property binding
In Angular, @Input() is a decorator that allows you to pass data from a parent component to a child component. It is
commonly used to create a communication channel between components, enabling the parent component to pass data down
to its child components.
In the ParentComponent, the child component ( <app-child> ) is used, and the [childMessage] binding is used to pass the
value of parentMessage to the childMessage property in the child component.
Changes to parentMessage in the parent component will automatically update the childMessage in the child component due
to the data binding.
31
@Output & Custom event binding
In Angular, the @Output() decorator is used to create an output property in a component. Output properties enable a child
component to emit events that a parent component can listen to. This mechanism allows child components to communicate
with their parent components.
The sendMessage() method in the ChildComponent is called when the button is clicked, and it emits the message through the
messageEvent output property.
In the ParentComponent, the child component ( <app-child> ) is used, and the (messageEvent) event binding is used to listen
for events emitted by the child component. The receiveMessage($event) method is called when the event occurs, and it
updates the receivedMessage property in the parent component.
33
Two way communication
Using @Input and @Output for the same variable allows you to establish a two-way communication between a parent
component and a child component in Angular. This is often referred to as two-way binding, and it can be achieved by
combining the use of @Input and @Output on the same property.
// child.component.ts
import { Component, EventEmitter, Input, Output } from '@angular/core';
@Component({
selector: 'app-child',
template: `
<input [(ngModel)]="childMessage" placeholder="Enter message in child">
<button (click)="sendMessage()">Send Message to Parent</button>`,
})
export class ChildComponent {
@Input() childMessage: string; // Input property
@Output() childMessageChange = new EventEmitter<string>(); // Output property
sendMessage() {
this.childMessageChange.emit(this.childMessage);
}
} 34
// parent.component.ts
@Component({
selector: 'app-parent',
template: `
<app-child [(childMessage)]="parentMessage"></app-child>
<p>Parent Message: {{ parentMessage }}</p>
`,
})
export class ParentComponent {
parentMessage: string = 'Hello from parent!';
}
35
Content projection with ng-content
You often need to create components that act as containers for different types of content. For example, you may want to create
a custom card component:
You can use the <ng-content> element as a placeholder to mark where content should go:
// Component source
@Component({
selector: 'custom-card',
template: '<div class="card-shadow"> <ng-content /> </div>',
})
export class CustomCard {/* ... */}
Each @let block can declare exactly one variable. You cannot declare multiple variables in the same block with a comma.
38
Attribute directives
Change the appearance or behavior of DOM elements and Angular components with attribute directives.
ng generate directive highlight
<!--src/app/app.component.html-->
<p appHighlight>Highlight me!</p>
39
Routing
In a single-page app, you change what the user sees by showing or hiding portions of the display that correspond to particular
components, rather than going out to the server to get a new page.
Import the routes into app.config.ts and add it to the provideRouter function. The following is the default
ApplicationConfig using the CLI.
41
Routing
You also need to add the RouterLink, RouterLinkActive, and RouterOutlet to the imports array of AppComponent.
@Component({
selector: 'app-root',
standalone: true,
imports: [CommonModule, RouterOutlet, RouterLink, RouterLinkActive],
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'routing-app';
}
42
Routing
Displaying a 404 page:
To display a 404 page, set up a wildcard route with the component property set to the component you'd like to use for your
404 page as follows:
The last route with the path of ** is a wildcard route. The router selects this route if the requested URL doesn't match any of
the paths earlier in the list and sends the user to the PageNotFoundComponent .
43
Forms
Angular provides two different approaches to handling user input through forms: reactive and template-driven. Both capture
user input events from the view, validate the user input, create a form model and data model to update, and provide a way to
track changes.
Template-Driven Forms:
Simpler to use.
Driven by directives in the template.
Two-way data binding with ngModel.
Reactive Forms:
44
Template-Driven Forms:
Template-driven forms are a simpler way to work with forms in Angular. They are driven by directives in the template and
require less explicit code.
<label for="email">Email:</label>
<input type="email" id="email" name="email" [(ngModel)]="formData.email" required>
<button type="submit">Submit</button>
</form>
45
// app.component.ts
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
formData: any = {}; // Object to store form data
submitForm(): void {
console.log('Form submitted:', this.formData);
// Add logic to process the form data
}
}
46
Reactive Forms
Reactive forms offer a more explicit and flexible way to work with forms in Angular. They are driven by form control instances
that you create programmatically in the component. Here are the basic steps for using reactive forms:
1. First, go to the src/app/app.component.ts file and import ReactiveFormsModule : import { FormsModule, NgForm,
ReactiveFormsModule } from '@angular/forms';
47
// app.component.ts
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet, FormsModule, ReactiveFormsModule],
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
myForm: FormGroup;
ngOnInit(): void {
this.myForm = this.fb.group({
name: ['', Validators.required],
email: ['', [Validators.required, Validators.email]],
});
}
submitForm(): void {
console.log('Form submitted:', this.myForm.value);
// Add logic to process the form data
}
}
48
3. Bind Form Controls to Template:
<label for="email">Email:</label>
<input type="email" id="email" formControlName="email">
<button type="submit">Submit</button>
</form>
Both template-driven and reactive forms have their use cases, and the choice between them depends on the requirements of
your application. Reactive forms are often preferred for larger and more complex forms due to their explicit nature and ease of
unit testing.
49
HttpClient
In Angular, the HttpClient module is used to make HTTP requests to a server and handle the responses. It provides a higher-
level API for sending and receiving data over HTTP/HTTPS and is part of the @angular/common/http module.
HttpClient is provided using the provideHttpClient helper function, which most apps include in the application providers
in app.config.ts .
You can then inject the HttpClient service as a dependency of an application class in a service:
50
HTTPClient
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError, retry } from 'rxjs/operators';
@Injectable({
providedIn: 'root',
})
export class RestApiService {
constructor(private http: HttpClient) { }
// Define API
private apiUrl = 'https://jsonplaceholder.typicode.com';
// Http Options
httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
}),
};
getData(): Observable<any> {
return this.http.get(`${this.apiUrl}/posts/1`);
}
51
Observables are a fundamental part of RxJS and are used to represent asynchronous data streams. They can be used for
handling events, promises, HTTP responses, and more.
// my-component.component.ts
@Component({
selector: 'app-my-component',
template: '<div>{{ responseData | json }}</div>',
})
export class MyComponent implements OnInit {
responseData: any;
ngOnInit() {
this.getData();
}
getData(): void {
this.myApiService.getData().subscribe((data) => {
this.responseData = data;
});
}
}
52
Observable streams can emit errors, and RxJS provides operators like catchError for handling errors.
// ...
getData(): void {
this.myApiService.getData().pipe(
catchError((error) => {
console.error('Error:', error);
throw error; // Rethrow the error or return a fallback value
})
).subscribe((data) => {
this.responseData = data;
});
}
53
TP
Create a CRUD application for Shows
A show have a title, a discription and the number of episodes.
Use Json server to get a full fake REST API
54