TIL, 2022-09-01, Components
Parse, don’t validate, incoming data in TypeScript.
- Runtypes, Zod, and
io-ts
are all runtime type validators that can parse your data into a specific type (or fail). - The type is the schema and is also the parser. We raise errors if the data was wrong, and we also have a TS type created.
- The “parse, don’t validate” mantra is all about parsing incoming data to a specific type, or failing in a controlled manner if the parsing fails. It’s about using trusted, safe and typed data structures inside your code and making sure all incoming data is handled at the very edges of your programs. Don’t pass incoming data deep into your code, parse it right away and fail fast if needed.
Here’s what you should know when creating flexible and reusable components in Angular
- The base idea of reusable and flexible components is simple. You have a reusable host component. This component contains some standard behaviour and template which is always the same.
- Defining slots - these are where the flexible content will end up.
- Modern browsers support
slot
andtemplate
<template id="foo">
<style>
h4 { color: blue }
</style>
<h4><slot name="title"></slot></h4>
</template>
Angular
ng-template
has the ability to hold content without rendering it. It’s the mechanism tongIf
andngFor
.- Most basic example:
<ng-template #theTruth>
<h4>Real Madrid - best football club ever</h4>
</ng-template>
<heading [title]="theTruth"> </heading>
<ng-container *ngTemplateOutlet="title"></ng-container>
ng-content
is likeslot
- allows us to specify spots in the host components. Those spots define where the dynamic content will end up.- When projecting content via
ng-content
, the lifecycle hooks are bound to the life cycle of the parent component.ngOnInit
is called once the host is renderedngOnDestroy
is called once the host is destroyed- Removing and rendering the projected content via
ngIf
doesn’t call the life cycles. - This can cause issues with
ngOnDestroy
if the streams are never properly unsubscribed.
ng-template
- is way less readable thanng-content
.- Mimic
ng-content
withng-template
- done withContentChild
.
<expander>
<ng-template>
<clock></clock>
</ng-template>
</expander>
Difference between ElementRef and TemplateRef
ElementRef
refers to an element of the DOM. Reference ContainsnativeElement
.- This is simply like
document.getElemenetById("myId")
.
- This is simply like
TemplateRef
represents an embedded template. Reference Can be used to instantiate embedded views.- You can use in
ViewContainerRef.createEmbeddedView
.
- You can use in
Exploring Angular DOM manipulation techniques using ViewContainerRef
ViewChild
andViewChildren
: They behave the same, and are paired with template reference variables.
Copy
@Component({
selector: 'sample',
template: `
<span #tref>I am span</span>
`
})
export class SampleComponent implements AfterViewInit {
@ViewChild("tref", {read: ElementRef}) tref: ElementRef;
ngAfterViewInit(): void {
// outputs `I am span`
console.log(this.tref.nativeElement.textContent);
}
}
- Parameter
read
is not always required, since Angular can infer the reference type by the type of the DOM element. ElementRef
- Just get the native element it’s associated with.- Angular doesn’t encourage this because I think it doesn’t run through change detection.
ViewChild
is used to get a reference to get a DOM element in its view (template).
TemplateRef
.- Templates work like this: The framework removes the
template
element and inserts a comment in its place.
- Templates work like this: The framework removes the
@Component({
selector: 'sample',
template: `
<ng-template #tpl>
<span>I am span in template</span>
</ng-template>
`
})
export class SampleComponent implements AfterViewInit {
@ViewChild("tpl") tpl: TemplateRef<any>;
ngAfterViewInit() {
let elementRef = this.tpl.elementRef;
// outputs `template bindings={}`
console.log(elementRef.nativeElement.textContent);
}
}
- It only has one method:
createEmbeddedView
. ViewRef
:- An Angular view is the smallest grouping of elements which are created and destroyed together. Angular philosophy encourages developers to see the UI as a composition of Views, not as a tree of standalone HTML tags.
- Creating a host view: This is when a component gets instantiated.
constructor(private injector: Injector,
private r: ComponentFactoryResolver) {
let factory = this.r.resolveComponentFactory(ColorComponent);
let componentRef = factory.create(injector);
let view = componentRef.hostView;
}
ViewContainerRef
- A container where one or more views can be attached.
- Angular doesn’t insert views inside the element, but appends them to the element bound to
ViewContainer
.
@Component({
selector: 'sample',
template: `
<span>I am first span</span>
<ng-container #vc></ng-container>
<span>I am last span</span>
`
})
export class SampleComponent implements AfterViewInit {
@ViewChild("vc", {read: ViewContainerRef}) vc: ViewContainerRef;
ngAfterViewInit(): void {
// outputs `template bindings={}`
console.log(this.vc.element.nativeElement.textContent);
}
}
- The API for creating views:
class ViewContainerRef {
...
clear() : void
insert(viewRef: ViewRef, index?: number) : ViewRef
get(index: number) : ViewRef
indexOf(viewRef: ViewRef) : number
detach(index?: number) : ViewRef
move(viewRef: ViewRef, currentIndex: number) : ViewRef
}
ngTemplateOutlet
: makes a DOM element as aViewContainer
and inserts an embedded view created by a template.ngComponentOutlet
creates a host view.
Understanding ViewContainerRef
in Angular 2
- A DOM element (container) where I can put your newly component as a sibling to this element.
@Component({
selector: 'vcr',
template: `
<template #tpl>
<h1>ViewContainerRef</h1>
</template>
`,
})
export class VcrComponent {
@ViewChild('tpl') tpl;
constructor(private _vcr: ViewContainerRef) {
}
ngAfterViewInit() {
this._vcr.createEmbeddedView(this.tpl);
}
}
@Component({
selector: 'my-app',
template: `
<vcr></vcr>
`,
})
export class App {
}