challenge 4 complete

This commit is contained in:
thomas laforge
2022-11-11 21:51:34 +01:00
parent ce393277a2
commit 0bc65cd6da
7 changed files with 60 additions and 66 deletions

View File

@@ -17,11 +17,12 @@ This goal of this project is to help you get better at Angular and NgRx buy reso
<img src="https://img.shields.io/badge/Angular--red?logo=angular" alt="Angular"/>
<a href="./apps/projection/README.md"><img src="https://img.shields.io/badge/1-Projection-red" alt="Projection"/></a>
<a href="./apps/ngfor-enhancement/README.md"><img src="https://img.shields.io/badge/2-Directive enhancement-red" alt="Directive enhancemen"/></a>
<a href="./apps/ngfor-enhancement/README.md"><img src="https://img.shields.io/badge/3-Directive enhancement-red" alt="Directive enhancement"/></a>
<a href="./apps/context-outlet-type/README.md"><img src="https://img.shields.io/badge/4-ContextOutlet Typed-red" alt="Directive enhancemen"/></a>
<img src="https://img.shields.io/badge/NgRx--blueviolet" alt="NgRx"/>
<a href="./apps/ngrx-1/README.md"><img src="https://img.shields.io/badge/1-effect vs selector-blueviolet" alt="Effect vs Selector"/></a>
<a href="./apps/ngrx-1/README.md"><img src="https://img.shields.io/badge/2-Effect vs Selector-blueviolet" alt="Effect vs Selector"/></a>
## License

View File

@@ -0,0 +1,45 @@
<h1>NgTemplateOutlet Strongly Typed</h1>
## Information
Angular offer the static function **ngTemplateContextGuard** to strongly type structural directive.
However the context of **NgTemplateOutlet** type is **Object**. But which the help of the above guard, we can improve that behavior.
## Statement
In this exercice, we want to learn how to strongly typed our ng-template in our AppComponent.
This exercice has two level of complexity.
### Level 1: known Interface
Currently we have the following piece of code.
<img src="./img/unknown-person.png" height=120px alt="Unkown Person"/>
As we can see, name is of type "any". We want to infer the correct type.
### Level 2: generic Interface
Currently we have the following piece of code.
<img src="./img/unknown-student.png" height=120px alt="Unkown Person"/>
As we can see, student is of type "any". We want to infer the correct type.
But in this part, we can pass to ListComponent, a list of any types. And we still want the correct type to be infered.
## Submitting your work
1. Fork the project
2. clone it
3. npm install
4. **nx serve context-outlet-type**
5. _...work On it_
6. Commit your work
7. Submit a PR with a title beginning with **Answer:4** that I will review and other dev can review.
<a href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A4+label%3Aanswer" target="_blank"><img src="https://img.shields.io/badge/-Solutions-green" alt="NgTemplateOutlet Strongly Typed"/></a>
_You can ask any question on_ <a href="https://twitter.com/laforge_toma" target="_blank"><img src="./../../logo/twitter.svg" height=20px alt="Twitter"/></a>

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View File

@@ -1,35 +1,29 @@
import { NgTemplateOutlet } from '@angular/common';
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { ListComponent, ListTemplateDirective } from './list.component';
import { PersonComponent, PersonDirective } from './person.component';
import { ListComponent } from './list.component';
import { PersonComponent } from './person.component';
@Component({
standalone: true,
imports: [
NgTemplateOutlet,
PersonDirective,
PersonComponent,
ListTemplateDirective,
ListComponent,
],
imports: [NgTemplateOutlet, PersonComponent, ListComponent],
selector: 'app-root',
template: `
<person [person]="person">
<ng-template person let-name let-age="age">
<ng-template #personRef let-name let-age="age">
{{ name }}: {{ age }}
</ng-template>
</person>
<list [list]="students">
<ng-container *appList="students as student; index as i">
<ng-template #listRef let-student let-i="index">
{{ student.name }}: {{ student.age }} - {{ i }}
</ng-container>
</ng-template>
</list>
<list [list]="cities">
<ng-container *appList="cities as city; index as i">
<ng-template #listRef let-city let-i="index">
{{ city.name }}: {{ city.country }} - {{ i }}
</ng-container>
</ng-template>
</list>
`,
changeDetection: ChangeDetectionStrategy.OnPush,

View File

@@ -3,32 +3,10 @@ import {
ChangeDetectionStrategy,
Component,
ContentChild,
Directive,
Input,
TemplateRef,
} from '@angular/core';
interface ListTemplateContext<TItem extends object> {
$implicit: TItem;
appList: TItem;
index: number;
}
@Directive({
selector: 'ng-template[appList]',
standalone: true,
})
export class ListTemplateDirective<TItem extends object> {
@Input('appList') data!: TItem[];
static ngTemplateContextGuard<TContextItem extends object>(
dir: ListTemplateDirective<TContextItem>,
ctx: unknown
): ctx is ListTemplateContext<TContextItem> {
return true;
}
}
@Component({
selector: 'list',
standalone: true,
@@ -50,6 +28,6 @@ export class ListTemplateDirective<TItem extends object> {
export class ListComponent<TItem extends object> {
@Input() list!: TItem[];
@ContentChild(ListTemplateDirective, { read: TemplateRef })
@ContentChild('listRef', { read: TemplateRef })
listTemplateRef!: TemplateRef<TItem[]>;
}

View File

@@ -1,35 +1,11 @@
import { NgTemplateOutlet } from '@angular/common';
import {
Component,
ContentChild,
Directive,
Input,
TemplateRef,
} from '@angular/core';
import { Component, ContentChild, Input, TemplateRef } from '@angular/core';
interface Person {
name: string;
age: number;
}
interface PersonContext {
$implicit: string;
age: number;
}
@Directive({
selector: 'ng-template[person]',
standalone: true,
})
export class PersonDirective {
static ngTemplateContextGuard(
dir: PersonDirective,
ctx: unknown
): ctx is PersonContext {
return true;
}
}
@Component({
standalone: true,
imports: [NgTemplateOutlet],
@@ -47,6 +23,6 @@ export class PersonDirective {
export class PersonComponent {
@Input() person!: Person;
@ContentChild(PersonDirective, { read: TemplateRef })
personTemplateRef!: TemplateRef<PersonContext>;
@ContentChild('#personRef', { read: TemplateRef })
personTemplateRef!: TemplateRef<unknown>;
}