# Review No. 2

In 
Published 2024-11-10

This page contains questions to improve/test your Angular skills.

# Is a service part of a Module ?

A service is not a part of a Module as a Component, a Directive or a Pipe. A service could be injected into a Component or into a service to be used.

# How can we make a service injectable ?

His can be done by using @Injectable annotation of the service class level.

@Injectable({
  providedIn: 'root'
})

NOTE: providedIn: 'root' says that the service can be used in any module of the application.

# How can we inject a service into a component ?

We can use dependency injection by adding the service as a parameter in the component’s constructor.

# Can we use a service without being injected ?

Yes, when

  1. the service class contains only static methods, so that can be used directly
export class MathUtils {
  static add(a: number, b: number): number {
    return a + b;
  }
}
const result = MathUtils.add(2, 3);
  1. we create an instance of a class directly with new keyword.
export class SimpleLogger {
  log(message: string) {
    console.log(message);
  }
}
const logger = new SimpleLogger();
logger.log("This is a log message.");

# What "export class" is doing ?

export class is a way to define a class and make it exportable so it can be imported and used in other files.

# How we can pass a value from a Parent Component to a Child Component ?

// parent.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-parent',
  template: `
    <h2>Parent Component</h2>
    <app-child [message]="parentMessage"></app-child> <!-- Passing data to the child component -->
  `
})
export class ParentComponent {
  parentMessage: string = 'Hello from Parent!';
}
// child.component.ts
import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-child',
  template: `
    <p>Message from parent: </p>
  `
})
export class ChildComponent {
  @Input() message: string = ''; // This property receives data from the parent
}

# How we can pass a value from a Child Component to a Parent Component ?

// parent.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-parent',
  template: `
    <h2>Parent Component</h2>
    <app-child (messageEvent)="receiveMessage($event)"></app-child> <!-- Listening to the child event -->
    <p>Message from child: </p>
  `
})
export class ParentComponent {
  childMessage: string = '';

  receiveMessage(message: string) {
    this.childMessage = message; // Update parent component's property with child data
  }
}
// child.component.ts
import { Component, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'app-child',
  template: `
    <button (click)="sendMessage()">Send Message to Parent</button>
  `
})
export class ChildComponent {
  @Output() messageEvent = new EventEmitter<string>();

  sendMessage() {
    this.messageEvent.emit('Hello from Child!'); // Emit an event with data
  }
}

# Can we have multiple <router-outlet> tags in different components ?

YES, especially when working with nested or "child" routes.

# ActivatedRoute, Router classes

  • Router -> for routing
  • ActivatedRoute -> for getting information about the activated route (data, parameters)

# What is InjectionToken class ?

InjectionToken class is used for creating a custom token for dependency injection (DI). Useful when we want to inject an object:

  • which is not a class (string, any other object)
  • you want to use interfaces for services

Step 1: Create the Token

// app-config.ts
import { InjectionToken } from '@angular/core';

export interface AppConfig {
  apiUrl: string;
  featureFlag: boolean;
}

// Create the InjectionToken with a description and optional type information
export const APP_CONFIG = new InjectionToken<AppConfig>('app.config');

Step 2: Provide the Token Value in the Module

// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { APP_CONFIG, AppConfig } from './app-config';
import { AppComponent } from './app.component';

// Define the configuration object
const APP_SETTINGS: AppConfig = {
  apiUrl: 'https://api.example.com',
  featureFlag: true
};

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule],
  providers: [
    { provide: APP_CONFIG, useValue: APP_SETTINGS } // Provide the configuration using APP_CONFIG token
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

Step 3: Inject the token in the Configuration

// example.service.ts
import { Injectable, Inject } from '@angular/core';
import { APP_CONFIG, AppConfig } from './app-config';

@Injectable({
  providedIn: 'root'
})
export class ExampleService {
  constructor(@Inject(APP_CONFIG) private config: AppConfig) {
    console.log('API URL:', this.config.apiUrl);
  }

  getApiUrl() {
    return this.config.apiUrl;
  }
}

# @ViewChild

Create a reference to the child component. Using this reference we can modify the variables and call the methods inside the child component (automatically we can modify the DOM).

# ! and ? operators

A variable marked with "!" cannot be null sau undefined.

  • Use ? when the property or parameter is optional (it may or may not have a value).
  • Use ! when the property will be assigned later, but you’re confident it will have a value when accessed (e.g., @ViewChild in Angular).
  • Leave off both ! and ? when the property or parameter must have a value at all times.

# null vs undefined

let x;   // x is declared but not assigned, so it’s `undefined`            
console.log(x);     // Output: undefined

let x = null;        // x is explicitly set to "no value"
console.log(x);      // Output: null

# | symbol

In TypeScript, the | symbol represents a union type. It allows a variable to hold one of several types.

let x: string | null | undefined;

# Classes vs Interfaces

  • Classes: used when we want to instantiate and decorate an object
  • Interfaces : used when we want to declare a data structure or a contract

# ::ng-deep pseudo-class

::ng-deep is a pseudo-class in Angular used for styling elements within child components from a parent component’s stylesheet.

# @HostListener decorator

@HostListener is a decorator used within a component or directive class to listen to specific events on the host element (the element where the directive or component is applied).

import { Component, HostListener } from '@angular/core';

@Component({
  selector: 'app-hover-component',
  template: `<div [ngStyle]="{'background-color': bgColor}">
               Hover over this box
             </div>`,
  styles: ['div { padding: 20px; font-size: 16px; text-align: center; }']
})
export class HoverComponent {
  bgColor = 'lightgray';

  @HostListener('mouseenter') 
  onMouseEnter() {
    this.bgColor = 'lightblue';
  }

  @HostListener('mouseleave') 
  onMouseLeave() {
    this.bgColor = 'lightgray';
  }
}

# sessionStorage vs localStorage

sessionStorage

  • Single tab/window
  • Only until the tab/window is closed
  • About 5MB (varies by browser)

localStorage

  • Across all tabs/windows
  • Persists even after browser restarts
  • Long-term preferences, saved data About 5-10MB (varies by browser)