#
Review No. 2
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.
Info
- In this case we don't need to include the service in
providers
at the Module level. - If included in
providers
at the Component level, we will deal with a new instance of the service and not the one (singleton) created at the application level.
#
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
- 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);
- 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.");
Info
In this case, the Dependency Injection (DI) mechanism is bypassed and we need that the service we are using must not use the DI.
#
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)
Info
Both sessionStorage and localStorage are not inherently secure and should be used cautiously, especially when storing sensitive information.