Angular 2에서 템플릿 내의 유형 주조
Angular 프로젝트(Angular 4.0.0)를 진행하고 있는데 추상 클래스의 속성을 tongModel에 바인딩하는 데 문제가 있습니다. 속성에 액세스하려면 먼저 실제 클래스로 캐스팅해야 하기 때문입니다.
예를 들어, 저는 AbstractEvent 클래스가 있는데, 이 클래스는 확인란으로 설정하려면 vingModel을 통해 양방향 바인딩이 필요한 부울 속성 'accknowledged'를 가진 구체적인 구현 Event를 가지고 있습니다.
현재 DOM에 다음 요소가 있습니다.
<input type="checkbox" *ngIf="event.end" [(ngModel)]="(event as Event).acknowledged"
[disabled]="(event as Event).acknowledged">
안타깝게도 이로 인해 다음과 같은 오류가 발생하고 있습니다.
감지되지 않은 오류:[(이벤트로 이벤트)]의 8열에 있는 템플릿 구문 분석 오류: 파서 오류: Missing expected).인정된
검색해보니 템플릿 내에서 'as'를 사용할 때 지원되지 않기 때문일 수도 있다고 합니다.확실하진 않지만요.
또한 템플릿을 구동하는 내 타이프스크립트 파일에 이에 대한 함수를 작성하는 방법을 알아낼 수 없습니다. 이는 내가 필요로 하는 ngModel에 대한 양방향 바인딩이 끊어지기 때문입니다.
만약 누군가가 이 문제를 피하거나 각도가 있는 템플릿에서 활자 주조를 올바르게 수행할 방법이 있다면 저는 매우 감사할 것입니다!
만약 당신이 유형 조절에 신경 쓰지 않는다면.
Angular 8 이상 버전에서는
[(ngModel)]="$any(event).acknowledged"
공식 문서에서: https://angular.io/guide/template-typecheck#disabling-type-checking-using-any
@Component({
selector: 'my-component',
template: '{{$any(person).addresss.street}}'
})
class MyComponent {
person?: Person;
}
그건 불가능해요 왜냐면Event템플릿 내에서 참조할 수 없습니다.
(as템플릿 바인딩 식에서도 지원되지 않음)
먼저 사용할 수 있도록 설정해야 합니다.
class MyComponent {
EventType = Event;
그러면 이것은 효과가 있을 것입니다.
[(ngModel)]="(event as EventType).acknowledged"
갱신하다
class MyComponent {
asEvent(val) : Event { return val; }
그러면 그것을 로 사용합니다.
[(ngModel)]="asEvent(event).acknowledged"
이 파이프는 다양한 입력에서 유형을 가져오는 데 사용할 수 있습니다.클래스, 이름이 지정된 유형/인터페이스 및 원시 클래스에서 매우 잘 작동합니다.
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'as',
pure: true,
})
export class AsPipe implements PipeTransform {
transform<T>(value: any, _type: (new (...args: any[]) => T) | T): T {
return value as T;
}
}
_type인수는 사용되지 않지만 주요 목표에 부합합니다. 유형은 생성자/변수에서 유추됩니다.
다음 용도로 사용할 수 있습니다.
class ClassEvent {
prop: string;
}
interface InterfaceEvent {
prop: string;
}
export class MyComponent {
MyClass = ClassEvent; // class constructor
MyInterface: InterfaceEvent; // typed property
propString: any; // primitive, string
propNumber: any; // primitive, number
}
<td mat-cell *matCellDef="let row">
Type from class constructor: {{ (row | as : MyClass).prop }}
Type from interface: {{ (row | as : MyInterface).prop }}
Type from primitive, string: {{ (propString | as : '').substr(1) }}
Type from primitive, number: {{ (propString | as : 123).toFixed(2) }}
</td>
엄격한 템플릿과 Ivy가 필요합니다.
앞서 언급했듯이 베어본 메소드 호출을 사용하면 성능에 영향을 미칩니다.
더 나은 접근법은 파이프를 사용하는 것이고, 두 가지 모두의 장점을 가지고 있습니다.주형 파이프 정의:
@Pipe({
name: 'cast',
pure: true
})
export class CastPipe implements PipeTransform {
transform(value: any, args?: any): Event {
return value;
}
}
템플릿에서 다음을 사용합니다.event | cast깁스가 필요할 때.
이렇게 하면 변경 감지가 효율적으로 유지되고 입력이 안전합니다(요청된 유형 변경이 당연하다는 점을 고려할 때).
안타깝게도, 저는 이것을 가질 방법을 찾지 못합니다. 왜냐하면,name각 유형에 대해 새 파이프를 정의해야 합니다.
내 TypeSafe 제네릭을 사용하여 다음과 같이 답합니다.
그리고 smnbbrv answer pass type에서 영감을 받아 유형을 추론할 곳이 없을 때 선택적 인수로 명시적으로 입력합니다.
import { Pipe, PipeTransform } from '@angular/core'; /** * Cast super type into type using generics * Return Type obtained by optional @param type OR assignment type. */ @Pipe({ name: 'cast' }) export class CastPipe implements PipeTransform { /** * Cast (S: SuperType) into (T: Type) using @Generics. * @param value (S: SuperType) obtained from input type. * @optional @param type (T CastingType) * type?: { new (): T } * type?: new () => T */ transform<S, T extends S>(value: S, type?: new () => T): T { return <T>value; } }용도:
template.vmdk
<input type="checkbox" *ngIf="event.end" [(ngModel)]="(event | cast: Event).acknowledged" [disabled]="(event | cast: Event).acknowledged" />구성 요소.ts
export abstract class AbstractEvent { end: boolean; } export class Event extends AbstractEvent { acknowledged: boolean; } export class MyComponent{ event: AbstractEvent; Event = Event; }
@smnbbrv로 답변을 확장하려면 다음과 같이 인터페이스와 유사한 구문을 사용할 수 있습니다.
@Pipe({ name: 'as', pure: true })
export class AsPipe implements PipeTransform {
transform<T>(input: unknown, baseItem: T | undefined): T {
return (input as unknown) as T;
}
}
따라서 올바른 유형의 "baseItem"을 제공해야 합니다.그러나 실제로 항목을 생성할 필요는 없으며 항목을 정의할 수 없으므로 선언만 하면 됩니다.즉, 다음과 같이 클래스에서 제안된 유형의 변수를 만들 수 있습니다.
export interface Person{
name: string;
age: number;
}
export class MyComponent {
Person: Person;
}
참고로, 우리는 어떤 값도 할당하지 않습니다.baseItem우리는 단지 그것의 유형을 지정하는 것입니다.가지고 계신다면,strictPropertyInitialization활성화된 경우, 당신은 당신의 비선택적 주장을 추가해야 할 것입니다.baseItem
export class MyComponent {
Person!: Person;
}
그런 다음 템플릿에서 다음과 같이 사용할 수 있습니다.
<td mat-cell *matCellDef="let row">
{{ (row | as : Person).name }}
</td>
app.component.vmdk
<some-component *ngIf="isFoo(foo)" [foo]="foo"></some-component>
app.component.ts
isFoo(value: Foo | Bar): value is Foo {
return value === 'Foo';
}
하면 템플릿 변수가 됩니다.foo타이핑하는Foo조합 유형과 관련된 모든 엄격한 템플릿 오류를 잠재웁니다.
면책 조항!저는 형식 주조 템플릿 변수에 대한 파이프 및 지침이 있는 ng-as Angular 라이브러리의 저자입니다.
직동형 주조(예:
import { Component } from '@angular/core';
// your interface, but also work with any typescript type (class, type, etc.)
interface Person {
name: string;
}
@Component({
selector: 'app-root',
template: `
<ng-container *ngTemplateOutlet="personTemplate; context: {$implicit: person}"></ng-container>
<ng-template #personTemplate [ngAs]="Person" let-person>
<span>Hello {{ person.name }}!</span>
</ng-template>
`,
})
export class AppComponent {
// NOTE: If you have "strictPropertyInitialization" enabled,
// you will need to add a non-null assertion (!)
public Person!: Person; // publish your interface into html template
person: Person = { name: 'Simone' }; // the data
}
파이프를 사용한 주조(예:
import { Component } from '@angular/core';
// your interface, but also work with any typescript type (class, type, etc.)
interface Person {
name: string;
}
@Component({
selector: 'app-root',
template: `
<ng-container *ngTemplateOutlet="personTemplate; context: {$implicit: person}"></ng-container>
<ng-template #personTemplate let-person>
<span>Hello {{ (person | as: Person).name }}!</span>
</ng-template>
`,
})
export class AppComponent {
// NOTE: If you have "strictPropertyInitialization" enabled,
// you will need to add a non-null assertion (!)
public Person!: Person; // publish your interface into html template
person: Person = { name: 'Simone' }; // the data
}
파이프 소스:
import { Pipe, PipeTransform } from "@angular/core";
@Pipe({ name: 'as', pure: true })
export class NgAsPipe implements PipeTransform {
// eslint-disable-next-line no-unused-vars
transform<T>(input: unknown, baseItem: T | undefined): T {
return input as unknown as T;
}
}
지시 출처:
import { Directive, Input } from "@angular/core";
interface NgAsContext<T> {
ngLet: T;
$implicit: T;
}
@Directive({ selector: '[ngAs]' })
export class NgAsDirective<T> {
@Input() ngAs!: T;
static ngTemplateContextGuard<T>(dir: NgAsDirective<T>, ctx: any): ctx is NgAsContext<Exclude<T, false | 0 | '' | null | undefined>> {
return true;
}
}
더 많은 정보: https://www.npmjs.com/package/ng-as
이것은 여전히 Angular에서 지원되지 않습니다.사용자 정의 파이프 또는 유형 지정할 함수를 만들 수 있습니다.
또는 $any()라는 구문을 사용하여 'any'로 캐스팅할 수 있습니다.
예:
{{$any(person).address.street}}
참조 문서: https://angular.io/guide/template-typecheck
언급URL : https://stackoverflow.com/questions/45964576/type-casting-within-a-template-in-angular-2
'programing' 카테고리의 다른 글
| 자바스크립트에서 TCP 소켓을 통해 통신하려면 어떻게 해야 합니까? (0) | 2023.08.25 |
|---|---|
| 빠른 인라인 조건부? (0) | 2023.08.25 |
| 부트스트랩 2를 사용하는 일부 위치에서는 글리피콘의 색상을 파란색으로 변경합니다. (0) | 2023.08.25 |
| exec("mysqdump")에서 2를 반환하지만 명령줄에서 명령이 작동합니다. (0) | 2023.08.25 |
| express.js를 사용하여 Ajax 호출에서 CSRF 보호를 구현하는 방법(완전한 예 찾기)? (0) | 2023.08.20 |