typescript - Typové konverzie v rámci šablóny v Angular 2


Pracujem na projekte Angular (Angular 4.0.0) a mám problém s viazaním vlastnosti abstraktnej triedy na ngModel, pretože ju najprv musím pretypovať na konkrétnu triedu, ktorou v skutočnosti je, aby som mohol pristupovať k vlastnosti.

t.j. mám triedu AbstractEvent, ktorá má konkrétnu implementáciu Event, ktorá má boolean vlastnosť 'acknowledged', ktorú potrebujem dvojcestne prepojiť cez ngModel na nastavenie pomocou zaškrtávacieho políčka.

Aktuálne mám tento prvok v svojom DOM:

<input type="checkbox" *ngIf="event.end" [(ngModel)]="(event as Event).acknowledged" 
                                          [disabled]="(event as Event).acknowledged">

Bohužiaľ to vyhadzuje nasledujúcu chybu:

Neprehliadnutá chyba: Chyby analýzy šablóny: Chyba parsera: Chýba očakávaná ) na stĺpci 8 v [(event as Event).acknowledged]

Hľadanie na Googli naznačovalo, že to môže byť preto, že používanie 'as' nie je podporované pri jeho používaní vo vnútri šablóny? Hoci si tým nie som istý.

Tiež nedokážem prísť na to, ako jednoducho napísať funkciu pre to v mojom Typescript súbore, ktorý riadi šablónu, pretože by to narušilo dvojcestné viazanie na ngModel, ktoré potrebujem.

Ak má niekto nejaký spôsob, ako sa tomu vyhnúť alebo správne vykonať typové pretypovanie v šablónach Angular, veľmi by som to ocenil!

Odpoveď č. 1

Ak vám nezáleží na kontrole typu.

V Angular verzii 8 a vyšších

[(ngModel)]="$any(event).acknowledged"

Z oficiálneho dokumentu: https://angular.dev/tools/cli/template-typecheck

Nový dokument: https://angular.dev/tools/cli/template-typecheck

@Component({
  selector: 'my-component',
  template: '{{$any(person).addresss.street}}'
})
class MyComponent {
  person?: Person;
}

Odpoveď č. 2

To nie je možné, pretože Event nemôže byť referencovaný z vnútra šablóny.

(as nie je podporované ani v šablónových väzobných výrazoch) Najprv ho musíte sprístupniť:

class MyComponent {
  EventType = Event;

tak by to malo fungovať

[(ngModel)]="(event as EventType).acknowledged"

aktualizácia

class MyComponent {
  asEvent(val) : Event { return val; }

potom to použi ako

[(ngModel)]="asEvent(event).acknowledged"

Odpoveď č. 3

Tento pipe sa dá použiť na získanie typu z rôznych vstupov. Funguje celkom dobre s triedami, pomenovanými typmi/rozhraniami a primitívnymi typmi.

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;
  }

}

Argument _type sa nepoužíva, ale slúži hlavnému účelu: typ sa odvodzuje z konštruktora/premennej.

Môže byť použitý ako:

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: {{ (propNumber | as : 123).toFixed(2) }}
</td>

Vyžaduje prísne šablóny a Ivy.

Odpoveď č. 4

Ako už bolo spomenuté, použitie holého volania metódy bude mať vplyv na výkon.

Lepší prístup je použiť pipe a získate to najlepšie z oboch svetov. Stačí definovať Cast pipe:

@Pipe({
  name: 'cast',
  pure: true
})
export class CastPipe implements PipeTransform {  
  transform(value: any, args?: any): Event {
    return value;
  }
}

a potom vo vašej šablóne použite event | cast, keď potrebujete prevod.

Týmto spôsobom zostáva detekcia zmien efektívna a typovanie je bezpečné (za predpokladu, že požadovaná zmena typu je samozrejme správna).

Bohužiaľ, nevidím spôsob, ako to urobiť generické kvôli atribútu name, takže by ste museli definovať nový filter pre každý typ.

Súvisiace články