Skip to content

Component:

Components are the base building blocks of the application. It's a place where you can define logic and template altogether that can be reusable in the app. Each component consists of:

  • HTML template
  • Typescript class
  • CSS styles

To define a component we need a @Component() decorator, the decorate allow us to create a component with lots of configurations, here are the most notable ones:

  • selector: your component element name in HTML template
  • templateUrl: path to HTML template, if you don't specify this option you can define template directly in template option
  • stylesUrl: path to styles template, can be 1 or many
  • providers: Provide component-level service for the dependency inversion
  • changeDetection: Change detection strategy such as default or onPush
  • encapsulation: Allow option to make your styling global or encapsulated to this component only
  • standalone: An option to make a component standalone so it doesn't need to be declared in a module
  • imports: If standalone is enabled, we need to use this option as well in order to add other components in the template

Example:

typescript
@Component({
  selector: 'app-component',
  templateUrl: './your-component.component.html',
  stylesUrl: ['./your-component.component.css']
})

Directives

Compared to a component, directive is a class that can modify the behavior of an HTML element or a component. directive apply directly to an element so we don't need to declare a template for it.
directive also implements lifecycle methods same as a component Most popular directives are:

  • Structural directives: *ngIf, *ngFor
  • Attribute directives: ngClass, ngModel

Directive composition API (Angular 15) [Docs](Angular - Directive composition API)

The API lets you apply directives to a component's host element from within the component TypeScript class.

Pipes

Pipes are special functions that are used in HTML templates to transform/modify display values. Pipes can be chained together to output the desired value. By using pipes, you have increased the reusability of the code base by declaring the transformation function once. So it can be used across many templates.

Usage:

html
<span>{{ date | datePipe }}</span> <!-- Transform Date object into date string -->
<span>{{ totalValue | currency }} <!-- Transform number in to currency string -->

Built-in pipes

NameDescription
AsyncPipeRead the value from a Promise or an RxJS Observable.
CurrencyPipeTransforms a number to a currency string, formatted according to locale rules.
DatePipeFormats a Date value according to locale rules.
DecimalPipeTransforms a number into a string with a decimal point, formatted according to locale rules.
I18nPluralPipeMaps a value to a string that pluralizes the value according to locale rules.
I18nSelectPipeMaps a key to a custom selector that returns a desired value.
JsonPipeTransforms an object to a string representation via JSON.stringify, intended for debugging.
KeyValuePipeTransforms Object or Map into an array of key value pairs.
LowerCasePipeTransforms text to all lower case.
PercentPipeTransforms a number to a percentage string, formatted according to locale rules.
SlicePipeCreates a new Array or String containing a subset (slice) of the elements.
TitleCasePipeTransforms text to title case.
UpperCasePipeTransforms text to all upper case.

Custom pipes

A pipe must have two things:

  • A name, specified in the pipe decorator
  • A method named transform that performs the value transformation.
typescript
// kebab-case.pipe.ts
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
  name: 'kebabCase',
})
export class KebabCasePipe implements PipeTransform {
  transform(value: string): string {
    return value.toLowerCase().replace(/ /g, '-');
  }
}

Services

Services are a class that have @Injector() decorator so it can be injected in components. Services can be used to call API or to hold application logic and state. [[Services]]

Input

Input data flow diagram of data flowing from parent to child We can pass data to child component using inputs. Angular now has 3 types of input

@Input

We can declare an input in a child component that data can be passed in. By using ngOnChanges() lifecycle, we can get the latest value each time the input changes.

Typescript
export class CustomCheckbox { 
	@Input() checked: boolean;

	ngOnChanges(changes: SimpleChanges) {
		//We can read value each time the input changes
		console.log(changes.checked);
	}
}

Signal input

Serve the same purposes as the original @Input, but with the benefit of signals. Why should we use signal inputs and not @Input()?

  • Type safe
  • Value can easily be derived and manipulated using signal computed()
  • More local monitoring by using effect() instead of ngOnChanges()
Typescript
export class CustomCheckbox { 
	//Optional input
	showLabel = input(false);
	
	//Required input
	disabled = input.required(false);
}

Model input

Model inputs • AngularModel inputs are a special type of input that enable a component to write new values back to parent component.

Typescript
export class CustomCheckbox { 
	// This is a model input. 
	checked = model(false); 
	// This is a standard input. 
	disabled = input(false);
}

Output

Output diagram of the data flow going from child to parent The usage of Output is for notify changes happenning in child component to the parent component

@Output

Takes an EventEmiiter then emit that event to the parent component

typescript
import { Output, EventEmitter } from '@angular/core';

// Child component declaration & properties...

@Output() newItemEvent = new EventEmitter<string>();

addNewItem(value: string) { 
	this.newItemEvent.emit(value); 
}

After we instantiate newItemEvent EventEmitter. We can now use emit() method to send value to parent component.

html
<child-component (newItemEvent)="handleEvent($event)">

The emitted event in child component will go through parent component handler function handleEvent with the $event argument as the value we have emitted. (newItemEvent) must be the same with the one declared with @Output

Output function

A function based output doesn't rely EventEmitter but still have the same functionality as @Output decorator. Angular now reccomends using output function instead of @Ouput:

  • Consistent with new APIs: Aligns with other function based APIs input() and model() signals, thus increase the typing/developer experience
  • Type safe: Stricter type compared to EventEmitter. Example: output() without passing type means void type. Meanwhile, EventEmitter() with no type is considered as any type
  • Simpler API: No longer use EventEmitter which inherit from RxJs Subject class. # OutputEmitterRef only has 2 methods subscribe() and emit()
  • Less boilerplate code: declaration is now shorter than @Ouput decorator

Resolvers

Class based or function based resolvers provide data to a route before navigation.
[[Resolvers]]

Guards

Functions to check whether route is allowed to navigate or not.
[[Guards]]

Routing

Is a module or config function to let user add routing config to application.
[[Angular Routing]]

Modules (NgModule)

[[Modules (@NgModule)]]