MODULE 8: Angular Fundamentals.
Introduction
Angular is a platform and framework for building single-page client applications using
HTML and TypeScript. Angular is written in TypeScript. It implements core and optional
functionality as a set of TypeScript libraries that you import into your applications.
The architecture of an Angular application relies on certain fundamental concepts. The basic
building blocks of the Angular framework are Angular components.
Components define views, which are sets of screen elements that Angular can choose among
and modify according to your program logic and data
Components use services, which provide background functionality not directly related to
views such as fetching data. Such services can be injected into components as dependencies,
making your code modular, reusable, and efficient.
Components and services are classes marked with decorators. These decorators provide
metadata that tells Angular how to use them.
The metadata for a component class associates it with a template that defines a view.
A template combines ordinary HTML with Angular directives and binding markup
that allow Angular to modify the HTML before rendering it for display.
The metadata for a service class provides the information Angular needs to make it
available to components through dependency injection (DI)
An application's components typically define many views, arranged hierarchically. Angular
provides the Router service to help you define navigation paths among views. The router
provides sophisticated in-browser navigational capabilities.
Components
Every Angular application has at least one component, the root component that connects a
component hierarchy with the page document object model (DOM). Each component defines
a class that contains application data and logic, and is associated with an HTML template that
defines a view to be displayed in a target environment.
The @Component() decorator identifies the class immediately below it as a component, and
provides the template and related component-specific metadata.
Templates, directives, and data binding
1
A template combines HTML with Angular markup that can modify HTML elements before
they are displayed. Template directives provide program logic, and binding markup connects
your application data and the DOM. There are two types of data binding:
Data Details
bindings
Event Lets your application respond to user input in the target environment by
binding updating your application data.
Property Lets you interpolate values that are computed from your application data into
binding the HTML.
Before a view is displayed, Angular evaluates the directives and resolves the binding syntax
in the template to modify the HTML elements and the DOM, according to your program data
and logic. Angular supports two-way data binding, meaning that changes in the DOM, such
as user choices, are also reflected in your program data.
Your templates can use pipes to improve the user experience by transforming values for
display. For example, use pipes to display dates and currency values that are appropriate for a
user's locale. Angular provides predefined pipes for common transformations, and you can
also define your own pipes.
Services and dependency injection
For data or logic that isn't associated with a specific view, and that you want to share across
components, you create a service class. A service class definition is immediately preceded by
the @Injectable() decorator. The decorator provides the metadata that allows other providers
to be injected as dependencies into your class.
Dependency injection (DI) lets you keep your component classes lean and efficient. They
don't fetch data from the server, validate user input, or log directly to the console; they
delegate such tasks to services.
Routing
The Angular Router package provides a service that lets you define a navigation path among
the different application states and view hierarchies in your application. It is modeled on the
familiar browser navigation conventions:
Enter a URL in the address bar and the browser navigates to a corresponding page
Click links on the page and the browser navigates to a new page
Click the browser's back and forward buttons and the browser navigates backward
and forward through the history of pages you've seen
The router maps URL-like paths to components instead of pages. When a user performs an
action, such as clicking a link, that would load a new component in the browser, the router
2
intercepts the browser's behavior, and shows or hides that component (and its child
components).
If the router determines that the current application state requires a component that hasn't
been loaded, the router can lazy-load that component and its related dependencies.
The router interprets a link URL according to your application's view navigation rules and
data state. You can navigate to new views when the user clicks a button or selects from a
drop box, or in response to some other stimulus from any source. The router logs activity in
the browser's history, so the back and forward buttons work as well.
To define navigation rules, you associate navigation paths with your components. A path
uses a URL-like syntax that integrates your program data, in much the same way that
template syntax integrates your views with your program data. You can then apply program
logic to choose which views to show or to hide, in response to user input and your own
access rules.
1. Introduction to Angular Framework & CLI
What is Angular?
Angular is a client-side (front-end) framework maintained by Google. It is used for
building Single Page Applications (SPAs).
It is built with TypeScript (a superset of JavaScript), which gives static typing,
modern JS features, decorators, etc.
Angular supports modularity, dependency injection, component-based architecture, a
templating syntax, reactive programming (via RxJS), routing, forms, HTTP clients,
and many built-in tools.
Angular (versions 2+) replaced AngularJS (version 1.x) with a more modern
architecture, better performance, easier testability, and better tooling.
What is Angular CLI?
CLI stands for Command Line Interface. Angular CLI is a tool to scaffold, build, test,
and deploy Angular applications.
It helps generate components, services, modules, directives, pipes, etc., following best
practices and project structure.
It also handles build configurations, environment configurations, bundling,
minification, etc.
Commands & Usage
Install CLI globally:
3
npm install -g @angular/cli
Create a new project:
ng new my-app
cd my-app
This creates a folder my-app with standard Angular project scaffold including src/, app/,
configuration files etc.
Serve / Development:
ng serve -o
ng serve runs a local dev server, -o usually opens the browser automatically.
Generate components, services, etc.:
ng generate component component-name
ng generate service service-name
ng generate module module-name
Build for production:
ng build --prod
Why Angular + CLI is beneficial
Faster setup and standardization
Enforces project structure that’s maintainable
Handles many tedious tasks (bundling, module loading, AOT, tree shaking)
Easier upgrades and consistency across projects
2. Angular Architecture & Ecosystem
Core Concepts & Architecture
Modules (@NgModule)
An NgModule groups related components, directives, pipes, and services. There is a
root module (often AppModule), and feature modules. Modules help in lazy loading,
separation of concerns, and organizing code.
4
Components (@Component)
Components are the basic units of UI. Each component has:
o A TypeScript class where logic resides
o A template (HTML)
o Styles (CSS/SCSS etc.)
o Metadata via decorator @Component
Templates
Templates are HTML files or inline HTML with Angular template syntax. They
include bindings (data binding), directives, etc.
Directives & Pipes
Directives modify the DOM or the behavior of elements (built-in ones like *ngIf,
*ngFor, ngClass etc.; custom ones you define). Pipes are used to transform data for
display (e.g. date, uppercase, custom pipes).
Services & Dependency Injection
Services are singleton or per-module/per-component logic providers (e.g. making
HTTP calls, shared data). Angular’s DI system allows components or other services to
receive these services via constructors.
Routing
Angular Router lets you define routes to map URLs to components. Supports features
like lazy loading, nested routes, route guards, parameterized routes.
Reactive Programming
Angular uses RxJS library heavily (Observables, Subjects) for asynchronous data
flows: HTTP, event streams, reactive forms, etc.
Ecosystem
Angular Material / CDK — UI component library
Third-party libraries — For charts, state management (NgRx, Akita), forms
(reactive or template driven), internationalization, animations etc.
Tools — Testing (Karma, Jasmine, Jest), linting (TSLint/ESLint), formatting,
build/deploy tools.
5
3. Project Setup & File Structure
When you scaffold a new project with ng new, you’ll see a structure like:
project-root/
│
├── src/
│ ├── app/
│ │ ├── [Link]
│ │ ├── [Link]
│ │ ├── [Link] (or .scss)
│ │ ├── [Link]
│ │ └── possibly feature folders with components, services, etc.
│ ├── assets/
│ ├── environments/
│ │ ├── [Link]
│ │ └── [Link]
│ ├── [Link]
│ ├── [Link]
│ ├── [Link]
│ ├── [Link] (or .scss)
│ └── other global files
│
├── [Link]
├── [Link]
├── [Link]
6
├── [Link]
├── [Link] / .eslintrc (lint config)
└── [Link]
Key parts
[Link]: Root module, which bootstraps the root component (often
AppComponent) and imports other modules.
[Link].*: Root component.
assets/: Static resources like images, icons.
[Link]: Configurations like API endpoints etc., different for dev/prod.
[Link]: Entry point of application — bootstraps Angular.
[Link]: Configuration for Angular CLI: build targets, file paths, styles, assets,
etc.
[Link]: TypeScript configuration – strictness, module targeting, etc.
4. TypeScript Essentials for Angular
Because Angular uses TypeScript, these are essential.
Basic Types
let name: string = "Alice";
let age: number = 30;
let active: boolean = true;
let list: string[] = ["one", "two"];
Interfaces & Types
interface User {
id: number;
username: string;
email?: string; // optional
}
type Status = "active" | "inactive";
7
Classes & Inheritance
class Person {
constructor(public name: string, protected age: number) {}
getInfo(): string {
return `${[Link]} is ${[Link]} years old.`;
}
}
class Employee extends Person {
constructor(name: string, age: number, public employeeId: number) {
super(name, age);
}
getEmployeeInfo(): string {
return `${[Link]()} Employee ID: ${[Link]}`;
}
}
Generics
function identity<T>(arg: T): T {
return arg;
}
let num = identity<number>(123);
let str = identity<string>("Hello");
Decorators
@Component, @NgModule, @Injectable, @Directive, @Pipe are decorators in
Angular.
Decorators allow attaching metadata.
Modules, Imports, Exports
Use ES6 module syntax.
Control visibility and shareability with export and import.
Async, Promises, Observables
HTTP, event streams typically deliver data asynchronously.
Observables (from RxJS) are powerful: map, filter, subscribe, pipe etc.
8
5. Components & Templates
Component Basics
// [Link]
import { Component } from '@angular/core';
@Component({
selector: 'app-example',
templateUrl: './[Link]',
styleUrls: ['./[Link]']
})
export class ExampleComponent {
title: string = "Hello from Example";
count: number = 0;
increment(): void {
[Link]++;
}
}
<!-- [Link] -->
<h2>{{ title }}</h2>
<button (click)="increment()">Increment</button>
<p>Count is {{ count }}</p>
Template Syntax
Interpolation: {{ variable }}
Property binding: [src]="imageUrl", [disabled]="isDisabled"
Event binding: (click)="doSomething()"
Two-way binding: [(ngModel)]="modelValue"
Templates can include
Conditional rendering (*ngIf)
Iteration (*ngFor)
Nested components
9
Inputs/Outputs for child components
Pipes
Template reference variables etc.
6. Data Binding
Data binding connects the view (template) and component class.
Types of Data Binding
Type Direction Syntax Description
Interpolatio Component → {{ someProperty
Display property values in template
n Template }}
Property Component → [disabled]="isDi
Bind to element or DOM property
Binding Template sabled"
Event Template → (click)="onClick Handle DOM events, call component
Binding Component ()" methods
Two-Way Template ↔ [(ngModel)]="na Combine property + event binding;
Binding Component me" requires FormsModule
Examples
// in component
export class ExampleComponent {
name: string = "";
imageUrl: string = "assets/[Link]";
isVisible: boolean = true;
showAlert(msg: string): void {
alert(msg);
}
}
<!-- in template -->
<input [(ngModel)]="name" placeholder="Enter name">
<p>Hello, {{ name }}</p>
<img [src]="imageUrl">
<button (click)="showAlert('You clicked!')">Click me</button>
10
<div *ngIf="isVisible">
Visible content
</div>
Best Practices / Things to Watch
Use OnPush change detection strategy where possible for performance (requires
immutable data patterns).
Avoid heavy computations inside templates (use pipes or component methods, but be
careful with change detection).
When using two-way binding, know that it combines property + event; understand
where component state changes.
7. Built-in Directives (ngIf, ngFor, ngSwitch, ngClass, ngStyle)
Structural Directives (they alter DOM layout)
*ngIf
<div *ngIf="isLoggedIn">Welcome, user!</div>
*ngFor
<ul>
<li *ngFor="let item of items; let i = index">
{{ i }} - {{ item }}
</li>
</ul>
*ngSwitch
<div [ngSwitch]="role">
<p *ngSwitchCase="'admin'">Admin Dashboard</p>
<p *ngSwitchCase="'user'">User View</p>
<p *ngSwitchDefault>Guest</p>
</div>
Attribute Directives
ngClass
<p [ngClass]="{'active': isActive, 'disabled': !isActive}">
Some text
11
</p>
ngStyle
<p [ngStyle]="{ 'color': isActive ? 'green' : 'red', 'font-weight': isActive ? 'bold' : 'normal' }">
Styled text
</p>
Other built-ins
ngTemplate, ngContainer
ngIf else / then
Best Practices
For large lists, use trackBy with ngFor for performance.
Use ngIf else rather than multiple nested *ngIf.
Keep templates clean; move logic (computations) to component class or pipes if
necessary.
8. Angular Modules & Application Structure
NgModule
Declared via @NgModule decorator: declarations, imports, exports, providers,
bootstrap.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './[Link]';
import { SomeComponent } from './some/[Link]';
import { SomeModule } from './some/[Link]';
@NgModule({
declarations: [
AppComponent,
SomeComponent
],
imports: [
BrowserModule,
SomeModule
],
providers: [
12
// services if any
],
bootstrap: [AppComponent]
})
export class AppModule { }
declarations: components, directives, pipes that belong to this module.
imports: other modules whose exported classes are needed by components in this
module.
exports: components, directives, pipes that this module makes available to others.
providers: services or injectable dependencies; can be module-wide.
bootstrap: root component(s) to bootstrap at startup (usually only in root module).
Feature Modules & Lazy Loading
Divide large applications into feature modules.
Use lazy loading to improve startup time, only load modules/routes when needed.
Shared Modules
For components, directives, pipes that are used in multiple modules, group them in a
SharedModule, export what’s needed.
Core Module
For singleton services (application-wide), base components, and items you want
loaded once; create a CoreModule to hold these. Prevent import of CoreModule into
multiple modules.
9. Component Communication (Input, Output, EventEmitter)
When components need to communicate (parent-child, sibling, etc.), there are several
mechanisms.
Parent → Child: @Input
Parent passes data to a child component via property binding.
// [Link]
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-child',
template: `<p>Child: {{ childData }}</p>`
13
})
export class ChildComponent {
@Input() childData!: string;
}
<!-- [Link] -->
<app-child [childData]="parentValue"></app-child>
Child → Parent: @Output & EventEmitter
Child emits events to parent using @Output + EventEmitter.
// [Link]
import { Component, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-child',
template: `<button (click)="notifyParent()">Notify Parent</button>`
})
export class ChildComponent {
@Output() notify: EventEmitter<string> = new EventEmitter<string>();
notifyParent() {
[Link]("Hello from Child");
}
}
<!-- [Link] -->
<app-child (notify)="handleNotification($event)"></app-child>
Other Communication Modes
Service-based communication (especially between non-related components). Using
an injectable service with RxJS Subject/Observable to broadcast or share data.
ViewChild / ViewChildren to get component/directive instances inside a component
and call methods or access properties. (See below section on ViewChild)
Content projection (ng-content) for passing markup from parent into child.
Router parameters for components loaded via routing.
Best Practices
Keep component interface (Inputs/Outputs) minimal.
14
Use typed data contracts (interfaces) for data passed via Inputs/Outputs.
Avoid over-emitting or multiple layers of event chaining if a service or state
management may be more appropriate.
Clean up subscriptions / events to avoid memory leaks (especially with services).
10. Template Reference Variables & ViewChild
These allow more direct interaction between template elements (or child components) and the
component class.
Template Reference Variables
In template, prefix a variable with # to reference an element, directive, or component.
Example:
<input #myInput type="text">
<button (click)="log([Link])">Log value</button>
Can also reference a component:
<app-child #childComp></app-child>
<button (click)="[Link]()">Invoke</button>
ViewChild / ViewChildren
A decorator to get a reference in the component class to a template reference variable,
component, directive, or element in the view.
import { Component, ViewChild, AfterViewInit, ElementRef } from '@angular/core';
import { ChildComponent } from './[Link]';
@Component({ ... })
export class ParentComponent implements AfterViewInit {
@ViewChild('myInput') inputElement!: ElementRef<HTMLInputElement>;
@ViewChild(ChildComponent) childComp!: ChildComponent;
ngAfterViewInit(): void {
// inputElement is now available
[Link]([Link]);
// childComp is available
[Link]();
}
15
}
For multiple instances: @ViewChildren returns a QueryList.
@ViewChildren('childCompRef') children!: QueryList<ChildComponent>;
ngAfterViewInit() {
[Link](child => [Link]());
}
Lifecycle Hooks
ngAfterViewInit(): view and child views are initialized; ViewChild references are
available.
ngAfterViewChecked(): after each change detection for the view; can be used
carefully.
Things to consider / Best Practices
[Link] gives access to raw DOM; should be used sparingly.
Prefer Renderer2 if doing DOM manipulations (for cross-platform, security).
Ensure the referenced element or component exists (guard for undefined) because
*ngIf or structural directives may delay or remove it.
Avoid overly coupling parent to child implementation; better to use well-defined
component APIs (Inputs/Outputs) rather than reaching into child to manipulate
internal state.
11. Working with Angular Templates & Structural Directives
Templates + structural directives combine to produce dynamic, conditional, repeated, or
alternate layouts.
Structural Directives Recap
*ngIf: conditionally includes or removes a portion of DOM.
*ngFor: iterates over a collection.
*ngSwitch, *ngSwitchCase, *ngSwitchDefault: switch-case logic.
Advanced Template Techniques
ng-template: defines template fragment. Can be used for reuse, lazy loading, or
conditional rendering.
16
<ng-template #loading>
<p>Loading...</p>
</ng-template>
<div *ngIf="isLoading; else loading">
<p>Data loaded</p>
</div>
ng-container: a host element that doesn’t render any actual DOM tag; useful to group
structural directives without extra tags.
<ng-container *ngFor="let item of items">
<p>{{ item }}</p>
</ng-container>
Using trackBy in *ngFor:
<li *ngFor="let item of items; trackBy: trackByFn">...</li>
trackByFn(index: number, item: SomeType): any {
return [Link];
}
Conditional templates with ngIf else then to keep templates readable.
Best Practices
Keep templates clean; avoid putting complex logic inside template expressions (use
methods sparingly because they may run many times due to change detection).
Use pipes for formatting or small transformations rather than writing logic in
template.
Structure templates to minimize depth and nested conditionals when possible; deep
nesting reduces readability.
Use structural directives wisely; having too many *ngIfs can cause flicker or change
detection overhead.
12. Introduction to Angular Styling (Inline, External, Scoped Styles)
Angular supports different ways to apply styles to components and the application.
Inline Styles
17
Defined inside the styles property of @Component decorator.
@Component({
selector: 'app-inline',
template: `<p class="text">Inline style example</p>`,
styles: [`
.text {
color: blue;
font-size: 16px;
}
`]
})
export class InlineComponent { }
External Styles
CSS / SCSS (or other preprocessor) files referred via styleUrls.
@Component({
selector: 'app-external',
templateUrl: './[Link]',
styleUrls: ['./[Link]']
})
export class ExternalComponent { }
Global styles in e.g. [Link] or [Link] in src/ are applied application-wide.
Scoped / View Encapsulation
Each component by default uses Emulated view encapsulation, meaning styles
defined in a component apply to that component only (Angular scopes them with
generated attributes).
Alternatives: None (styles are global), ShadowDom (uses browser native shadow
DOM).
@Component({
selector: 'app-style-test',
templateUrl: './[Link]',
styleUrls: ['./[Link]'],
encapsulation: [Link] // or ShadowDom
})
export class StyleTestComponent { }
Best Practices in Styling
18
Prefer external components’ styles (via styleUrls) rather than massive inline styles.
Use SCSS or other preprocessors for nesting, variables, mixins etc.
Maintain consistent styling conventions (naming, theming).
Avoid using too much global CSS; isolate where possible.
For common styles, create shared style files or theming modules.
13. Angular Project Best Practices & Coding Standards
These are guidelines to maintain code quality, readability, maintainability, and performance.
Structure & Organization
Use feature modules to group related functionality.
Use SharedModule for reusable components/directives/pipes.
Use CoreModule for singleton services and functionality that should be loaded once.
Follow consistent directory structure (e.g. components/, services/, models/,
directives/, pipes/, assets/).
Naming Conventions
Files: component names as [Link], [Link],
etc.
Class names: PascalCase, matching the filename.
Components selectors: use kebab-case with prefix (e.g. app-, or custom prefix).
Coding Standards
Use TypeScript strict settings (no implicit any, strict null checks).
Avoid any type; use strong typing.
Use interfaces or types for data models.
Use linting tools (ESLint etc.).
Use Prettier or other formatting tools for consistent code style.
Performance Considerations
Use OnPush change detection strategy when possible.
Use lazy loading of modules for large apps.
Use trackBy with ngFor for lists.
Avoid complex logic inside templates.
19
Limit use of heavy watchers or subscriptions; unsubscribe when needed.
Testing
Write unit tests for components, services.
Use component integration tests.
Use end-to-end tests for flows.
Use mocks for services/external dependencies.
Security
Sanitize user inputs. Angular by default protects against XSS in interpolation, but be
aware when using innerHTML, etc.
Use Content Security Policy where appropriate.
Avoid direct DOM manipulation unless necessary; prefer abstractions.
Maintainability & Documentation
Write comments for complex logic.
Document component APIs (Inputs/Outputs).
Use consistent commit messages.
Use version control, code reviews.
14. Putting It All Together: Example Application (Illustrative)
Here is a mini example that demonstrates many of the above concepts in one toy app.
// [Link]
export interface User {
id: number;
name: string;
role: 'admin' | 'user' | 'guest';
}
// [Link]
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { User } from './[Link]';
@Injectable({
providedIn: 'root'
})
20
export class UserService {
private _userSubject = new BehaviorSubject<User | null>(null);
get user$(): Observable<User | null> {
return this._userSubject.asObservable();
}
setUser(user: User) {
this._userSubject.next(user);
}
}
// [Link]
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-role-display',
template: `
<p>User role: {{ role }}</p>
`,
styles: [`
p { font-weight: bold; }
`]
})
export class RoleDisplayComponent {
@Input() role!: string;
}
// [Link]
import { Component, AfterViewInit, ViewChild, ElementRef } from '@angular/core';
import { UserService } from './[Link]';
import { RoleDisplayComponent } from './[Link]';
import { User } from './[Link]';
@Component({
selector: 'app-parent',
template: `
<input #nameInput placeholder="Enter name">
<select #roleSelect>
<option value="admin">Admin</option>
<option value="user">User</option>
<option value="guest">Guest</option>
21
</select>
<button (click)="addUser()">Add User</button>
<ng-container *ngIf="currentUser; else noUser">
<h2>Welcome, {{ [Link] }}</h2>
<app-role-display [role]="[Link]"></app-role-display>
</ng-container>
<ng-template #noUser>
<p>No user selected.</p>
</ng-template>
`
})
export class ParentComponent implements AfterViewInit {
@ViewChild('nameInput') nameInputElem!: ElementRef<HTMLInputElement>;
@ViewChild('roleSelect') roleSelectElem!: ElementRef<HTMLSelectElement>;
currentUser: User | null = null;
constructor(private userService: UserService) { }
ngAfterViewInit(): void {
// optional: focus input
[Link]();
}
addUser() {
const name = [Link];
const role = [Link] as User['role'];
if (name) {
[Link]({ id: [Link](), name, role });
[Link]$.subscribe(user => [Link] = user);
}
}
}
This small example shows:
Model (interface), service (shared data)
Parent → Child communication via @Input
Template reference variables + ViewChild to access DOM elements
*ngIf + ng-template for conditional templates
Styling via component style (scoped)
22
Simple reactive data flow
23