CodeEazy

Angular Logo

Angular v20 Made Eazy

1. Introduction to Angular

What is Angular?

Angular is a powerful, open-source front-end web application framework developed and maintained by Google. It allows developers to build scalable, modular, and high-performance web applications using HTML, CSS, and TypeScript. Angular uses a component-based architecture and supports modern features such as two-way data binding, dependency injection, and reactive programming.

Why Angular? Features & Benefits

  • Component-Based Architecture: Simplifies UI development and promotes code reusability.
  • TypeScript: Offers static typing and advanced tooling for improved development experience.
  • Dependency Injection: Manages services efficiently and promotes maintainable code.
  • RxJS & Observables: Supports reactive programming for asynchronous data handling.
  • Built-in Routing: Provides seamless navigation and lazy loading of modules.
  • CLI Tooling: The Angular CLI accelerates development with commands for creating, building, and testing applications.

Understanding Angular Architecture

Angular is based on a modular architecture consisting of components, directives, services, and modules. At its core:

  • Modules: Organize application functionality into cohesive blocks.
  • Components: Control views (HTML) and logic (TypeScript) for each part of the UI.
  • Templates: Define the HTML structure using Angular directives and expressions.
  • Services: Handle business logic and data access, often shared across components.
  • Dependency Injection: Automatically provides services to components where needed.
  • Routing: Allows navigation between components with defined paths.

2. Setting Up the Development Environment

Installing Node.js and Angular CLI

To begin developing Angular applications, you need to install Node.js (which includes npm – Node Package Manager) and Angular CLI.

  1. Download and install Node.js from nodejs.org.
  2. Once installed, open a terminal and verify installation:
node -v
    npm -v

Now install Angular CLI globally using npm:

npm install -g @angular/cli

Verify Angular CLI installation:

ng version

Creating Your First Angular App

Use the Angular CLI to create a new application:

ng new my-first-app

The CLI will prompt you for options like routing and stylesheets. Choose your preferences.

Navigate to the app directory and serve the app:

cd my-first-app
    ng serve

Visit http://localhost:4200 in your browser to view your Angular application running locally.

Angular CLI Commands and Project Structure

Angular CLI helps generate code and manage your project efficiently.

  • ng generate component component-name — Creates a new component.
  • ng generate service service-name — Creates a new service.
  • ng build — Compiles the project for deployment.
  • ng test — Runs unit tests.
  • ng lint — Analyzes the code for style and errors.

Typical Angular folder structure:

src/
     ┣ app/
     ┃ ┣ components/
     ┃ ┣ services/
     ┃ ┗ app.module.ts
     ┣ assets/
     ┗ index.html

3. Components and Templates

Creating Components using CLI

Components are the core building blocks of Angular applications. You can generate them using the Angular CLI:

ng generate component component-name

Component Metadata and Decorators

Each component is a class annotated with the @Component decorator which provides metadata that Angular uses to create and display the component.

import { Component } from '@angular/core';
    
    @Component({
      selector: 'app-example',
      templateUrl: './example.component.html',
      styleUrls: ['./example.component.css']
    })
    export class ExampleComponent {
      title = 'Hello Angular';
    }

Data Binding – Interpolation, Property & Event Binding

  • Interpolation: Embed dynamic content using {{ expression }}
  • Property Binding: Bind data from class to view with [property]
  • Event Binding: Capture user actions with (event)
<h1>{{ title }}</h1>
    <img [src]="imageUrl" />
    <button (click)="onClick()">Click Me</button>

Two-way Binding with ngModel

Two-way binding keeps the input field and component in sync. Import FormsModule and use:

<input [(ngModel)]="userName" />
    <p>Welcome, {{ userName }}</p>

Component Interaction using @Input() and @Output()

Pass data from parent to child using @Input() and from child to parent using @Output() with EventEmitter.

// child.component.ts
    @Input() item: string;
    @Output() notify = new EventEmitter();
    
    sendMessage() {
      this.notify.emit('Message from child');
    }
// parent.component.html
    <app-child [item]="parentData" (notify)="handleNotify($event)"></app-child>

4. Directives and Pipes

Built-in Structural Directives: *ngIf, *ngFor

Structural directives change the structure of the DOM. Examples include:

<div *ngIf="isVisible">Conditionally visible</div>
    
    <ul>
      <li *ngFor="let item of items">{{ item }}</li>
    </ul>

Attribute Directives: ngClass, ngStyle

Attribute directives modify the appearance or behavior of elements:

<div [ngClass]="{ 'highlight': isActive }">Styled Div</div>
    
    <div [ngStyle]="{ 'color': color, 'font-size': fontSize + 'px' }">Styled Text</div>

Creating Custom Directives

To create your own directive:

ng generate directive highlight

Example directive to change background color:

import { Directive, ElementRef, HostListener } from '@angular/core';
    
    @Directive({
      selector: '[appHighlight]'
    })
    export class HighlightDirective {
      constructor(private el: ElementRef) {
        el.nativeElement.style.backgroundColor = 'yellow';
      }
    }

Using Built-in Pipes

Pipes are used to transform output in templates:

{{ birthday | date:'longDate' }}
    {{ amount | currency:'USD' }}
    {{ user | json }}

Creating Custom Pipes

ng generate pipe capitalize

Example custom pipe:

import { Pipe, PipeTransform } from '@angular/core';
    
    @Pipe({
      name: 'capitalize'
    })
    export class CapitalizePipe implements PipeTransform {
      transform(value: string): string {
        return value.charAt(0).toUpperCase() + value.slice(1);
      }
    }

Usage: {{ 'angular' | capitalize }}

5. Services and Dependency Injection

Creating a Service with Angular CLI

Services are used to share data and functionality across components. You can generate a service using:

ng generate service data

Injecting Services into Components

Services are injected via the constructor of a component:

constructor(private dataService: DataService) {}
    
    ngOnInit() {
      this.items = this.dataService.getItems();
    }

Using providedIn: 'root'

This registers the service globally without needing to import it in a module's providers array:

@Injectable({
      providedIn: 'root'
    })
    export class DataService {
      getItems() {
        return ['Item1', 'Item2'];
      }
    }

Hierarchical Injection

You can scope a service to a specific module or component to create a new instance for that context. For example:

@Component({
      selector: 'app-child',
      templateUrl: './child.component.html',
      providers: [ScopedService]
    })
    export class ChildComponent {
      constructor(private scopedService: ScopedService) {}
    }

Each instance of this component will get a new instance of ScopedService.

6. Routing and Navigation

Setting Up Routing Module

Angular provides a built-in router that enables navigation between different components. You can configure routes in a routing module.

const routes: Routes = [
      { path: 'home', component: HomeComponent },
      { path: 'about', component: AboutComponent },
      { path: '', redirectTo: '/home', pathMatch: 'full' },
    ];
    
    @NgModule({
      imports: [RouterModule.forRoot(routes)],
      exports: [RouterModule]
    })
    export class AppRoutingModule {}

RouterOutlet and RouterLink

<router-outlet> acts as a placeholder that Angular dynamically fills based on the current route. Use routerLink directive for navigation.

<nav>
      <a routerLink="/home">Home</a>
      <a routerLink="/about">About</a>
    </nav>
    
    <router-outlet></router-outlet>

Route Parameters and Query Strings

You can pass dynamic values through route parameters:

{ path: 'product/:id', component: ProductComponent }

In the component:

constructor(private route: ActivatedRoute) {}
    
    ngOnInit() {
      const id = this.route.snapshot.paramMap.get('id');
    }

Query strings can be accessed with:

this.route.queryParams.subscribe(params => {
      console.log(params['search']);
    });

Child Routes and Lazy Loading

Nested routing allows embedding routes within other components. Lazy loading improves performance by loading modules only when needed.

const routes: Routes = [
      {
        path: 'admin',
        loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)
      }
    ];

Route Guards: AuthGuard and CanActivate

Guards restrict access to routes based on conditions such as authentication.

canActivate(): boolean {
      return this.authService.isLoggedIn();
    }

Apply in route:

{
      path: 'dashboard',
      component: DashboardComponent,
      canActivate: [AuthGuard]
    }

7. HTTPClient and REST API Integration

Using HttpClientModule

Angular provides the HttpClientModule in @angular/common/http to make HTTP requests.

// app.module.ts
    import { HttpClientModule } from '@angular/common/http';
    
    @NgModule({
      imports: [HttpClientModule]
    })
    export class AppModule {}

GET, POST, PUT, DELETE Requests

constructor(private http: HttpClient) {}
    
    // GET
    getUsers() {
      return this.http.get('https://api.example.com/users');
    }
    
    // POST
    createUser(user: any) {
      return this.http.post('https://api.example.com/users', user);
    }
    
    // PUT
    updateUser(id: number, user: any) {
      return this.http.put(`https://api.example.com/users/${id}`, user);
    }
    
    // DELETE
    deleteUser(id: number) {
      return this.http.delete(`https://api.example.com/users/${id}`);
    }

Error Handling with catchError

You can handle HTTP errors using RxJS catchError operator.

import { catchError } from 'rxjs/operators';
    import { throwError } from 'rxjs';
    
    getData() {
      return this.http.get('/api/data').pipe(
        catchError(error => {
          console.error('Error:', error);
          return throwError(() => new Error('Something went wrong'));
        })
      );
    }

Handling Observables and Subscriptions

this.http.get('/api/data').subscribe({
      next: data => this.data = data,
      error: err => console.error('Error occurred:', err),
      complete: () => console.log('Request complete')
    });

Always unsubscribe to avoid memory leaks when not using async pipe.

ngOnDestroy() {
      this.subscription.unsubscribe();
    }

8. Forms in Angular

Template-Driven Forms

Template-driven forms are defined directly in the template using Angular directives like ngModel. Suitable for simple forms.

// app.module.ts
    import { FormsModule } from '@angular/forms';
    
    @NgModule({
      imports: [FormsModule]
    })
    export class AppModule {}

    

Reactive Forms

Reactive forms are built in the component class using FormGroup and FormControl. Suitable for complex forms.

// app.module.ts
    import { ReactiveFormsModule } from '@angular/forms';
    
    @NgModule({
      imports: [ReactiveFormsModule]
    })
    export class AppModule {}
// app.component.ts
    form = new FormGroup({
      email: new FormControl('', [Validators.required, Validators.email])
    });

    

FormGroup, FormControl, Validators

FormGroup is a collection of controls. FormControl tracks the value and validation status of individual form elements. Validators enforce rules like required or email.

this.form = new FormGroup({
      name: new FormControl('', Validators.required),
      email: new FormControl('', [Validators.required, Validators.email])
    });

Form Validation and Error Messages

You can check for validation errors and show helpful messages to users.


    
    
Email is required.
Invalid email format.

9. Angular Modules

Understanding NgModules

NgModules are containers that group components, directives, pipes, and services that are related. They help organize code into cohesive blocks and manage dependencies.

// app.module.ts
    @NgModule({
      declarations: [AppComponent, MyComponent],
      imports: [BrowserModule, FormsModule],
      providers: [],
      bootstrap: [AppComponent]
    })
    export class AppModule {}

Shared and Feature Modules

Shared modules contain reusable components, directives, and pipes. Feature modules group functionality by specific domains (e.g., ProductsModule).

// shared.module.ts
    @NgModule({
      declarations: [SharedComponent],
      exports: [SharedComponent],
      imports: [CommonModule]
    })
    export class SharedModule {}
// products.module.ts
    @NgModule({
      declarations: [ProductListComponent],
      imports: [CommonModule, SharedModule]
    })
    export class ProductsModule {}

Lazy Loading Modules

Lazy loading is a technique where modules are loaded on demand. This improves initial load performance.

// app-routing.module.ts
    const routes: Routes = [
      {
        path: 'products',
        loadChildren: () => import('./products/products.module').then(m => m.ProductsModule)
      }
    ];

10. Build and Deployment

Building Angular Application

Use the Angular CLI to build the production-ready version of your app. It optimizes and compiles TypeScript code into efficient JavaScript.

ng build --configuration production

Optimizing the Build

  • Use AOT (Ahead-of-Time) compilation (enabled by default in production build)
  • Enable build optimizer and minification
  • Remove unused dependencies and dead code
ng build --configuration production --base-href=/my-app/

Deploying to GitHub Pages

  • Install angular-cli-ghpages
npm install -g angular-cli-ghpages
    ng deploy --base-href=/my-app/

Deploying to Firebase Hosting

npm install -g firebase-tools
    firebase login
    firebase init
    ng build --configuration production
    firebase deploy

Deploying to Netlify

Drag and drop the contents of dist/ folder to Netlify UI or link your GitHub repo for automatic deployment.

  • Set build command: ng build --configuration production
  • Set publish directory: dist/my-app