angular - Hur skapar jag en karta från en klass för att extrahera dess egenskaper som värden?


Jag skulle vilja skapa en starkare typ-säker länk mellan en Angular-mall och en FormGroup. Jag tänkte på följande men jag vet inte hur jag ska uttrycka det korrekt i TypeScript.

Jag vill använda ett objekt för att ställa in nycklarna för controls-objektet i en FormGroup (den första parametern i FormControl-konstruktorn), samt bindningen av formControlName i mallen, med utgångspunkt från en modellklass.

Min resonemang är att detta kommer att ta bort den "stringiga" eller så kallade magic string API som uppstår från att använda strängar för formControlName-attributet. På detta sätt skulle den enda sanningskällan vara modellklassen. Detta skulle också göra det lätt för mig att refaktorera den klassen och få alla andra referenser uppdaterade.

Till exempel skulle jag ha velat kunna skriva något liknande detta:

// model class:
class Partner {
  id: string;
  name: string;
}

// some static type SomeType = { id: "id", name: "name" } extends Partner's public properties
// but the values of those properties must equal the property name.

// component:
@Component({
  template: `
    <form [formGroup]="form" (ngSubmit)="onSubmit()" novalidate>
      <!-- notice I'm not using a stringy API like formControlName="id" -->
      <input type="text" [formControlName]="SomeType.id">
      <input type="text" [formControlName]="SomeType.name">
    </form>
`})
class CreatePartnerComponent {
  form = new FormGroup({
    SomeType.id: new FormControl(''),
    SomeType.name: new FormControl('')
  });
}

Tack!

Svar #1

Jag verkar ha hittat ett sätt.

class ModelClass {
  id: string;
  name: string;
}

// for the template I need a literal object that I can access by key
// and provide form control names as strings to bind the formControlName
// directive to, so I declare this inside the component class:

readonly fcName: { [key in keyof ModelClass]: key } = {
  // the problem with this is you need to explicitly declare the properties here and
  // keep this property up to date when you refactor ModelClass, but you still
  // get an error if you forget to, so that's great.
  // Also some IDEs can auto-fill these properties along with the values as well.
  id: 'id',
  name: 'name'
}

// and bind form controls like [formControlName]="fcName.id" and so on,
// in the template, this should be pretty obvious by now.

// and the form group you now declare like this, which
// enforces correct key names based on the model:

form = new FormGroup({
  id: new FormControl(''),
  name: new FormControl('')
} as { [key in keyof ModelClass]: FormControl });

Finns det något annat mer elegant sätt att göra detta som kanske inte kräver att skapa den där fcNames (formulärkontrollnamn) variabeln, bara för att binda de korrekta namnen på formulärkontrollerna i mallen? Det är duplicerad kod som jag gärna skulle vilja eliminera om möjligt.

Svar #2

Detta kan vara lite sent, men det ser ut som att du helt enkelt kan använda setValue-metoden så här för att få detta gjort. this.formGroup.setValue(this.preFilledData)