Implementieren von Upsert-Formulardialogen in Angular

Dec 06 2022
Viele Anwendungen erfordern die Möglichkeit, Datensätze über die Benutzeroberfläche zu erstellen und zu aktualisieren. Normalerweise möchten wir dieselbe Dialogkomponente für beide Operationen verwenden.

Viele Anwendungen erfordern die Möglichkeit, Datensätze über die Benutzeroberfläche zu erstellen und zu aktualisieren. Normalerweise möchten wir dieselbe Dialogkomponente für beide Operationen verwenden. Der Begriff „Upsert“ ist eine Kombination aus den Wörtern „Update“ und „Insert“ und bezieht sich auf die Tatsache, dass der Dialog verwendet werden kann, um entweder einen neuen Datensatz zu erstellen oder einen vorhandenen zu aktualisieren.

Mal sehen, wie wir diese Funktionalität implementieren können. Ich werde die ngneat/dialogBibliothek verwenden, aber Sie können verwenden, was Sie bevorzugen. Zuerst erstellen wir eine gemeinsam genutzte Schnittstelle für die , die datawir an unseren Dialog übergeben müssen:

export interface UpsertDialogData<T> {
  action: 'add' | 'edit';
  actions$: Record<
    UpsertDialogData['type'],
    (value: T) => Observable<any>
  >;
  currentValue: T | undefined;
}

Lassen Sie uns nun die Basisdialogkomponente erstellen upsert:

import { DialogRef } from '@ngneat/dialog';
import { loadingFor } from '@ngneat/loadoff';
import { HotToastService } from '@ngneat/hot-toast';

@Directive()
export abstract class UpsertDialogComponent<Entity extends Record<string, any>>
  implements OnInit
{
  private toast = inject(HotToastService);
  loader = loadingFor('upsert');
  ref: DialogRef<UpsertDialogData<Entity>> = inject(DialogRef);

  abstract get form(): FormGroup;

  abstract getMessages(): Record<UpsertDialogData['action'], string>;

  get action() {
    return this.ref.data.action;
  }

  ngOnInit() {
    if (this.ref.data.action === 'edit') {
      this.form.patchValue(this.ref.data.currentValue);
    }
  }

  upsert() {
    if (this.form.invalid) return;

    this.ref.data.actions$[this.action](this.form.getRawValue())
      .pipe(this.loader.upsert.track())
      .subscribe(() => {
        this.ref.close();
        this.toast.success(this.getMessages()[this.action]);
      });
  }
}

Lassen Sie uns unsere Basisklasse verwenden und einen Dialog zum Einfügen eines Benutzers erstellen:

import { errorTailorImports } from '@ngneat/error-tailor';

@Component({
  standalone: true,
  imports: [errorTailorImports],
  templateUrl: `./upsert-user-dialog.component.html`
})
export class UpsertUserDialogComponent extends UpsertDialogComponent<User> {

  form = inject(FormBuilder).nonNullable.group({
    name: ['', Validators.required],
  });

  getMessages() {
    return {
      add: `User was added successfully`,
      edit: `User was updated successfully`,
    };
  }
}
<header>
  <h3>{{ action === 'edit' ? 'Edit User' : 'New User' }}</h3>
</header>

<div>
  <form [formGroup]="form" errorTailor>
     <input
        placeholder="Name"
        formControlName="name" />
  </form>
</div>

<footer>
  <button dialogClose>Cancel</button>
  <button
    [loading]="loader.upsert.inProgress$ | async"
    (click)="upsert()"
  >
    {{ action === 'edit' ? 'Save' : 'Create' }}
  </button>
</footer>

@Component({
  template: `
    <button (click)="openUpsertUserDialog('add')">Add User</button>

     <-- ngFor -->
    <button (click)="openUpsertUserDialog('edit', user)">Edit</button>
  `
})
export class UsersPageComponent {

  openUpsertUserDialog(
    action: UpsertDialogData['action'],
    currentValue?: UpsertDialogData<User>['currentValue']
  ) {
    this.dialogService.open(UpsertUserDialogComponent, {
      data: {
        action,
        currentValue,
        actions$: {
          add: (user) => this.usersService.addUser({ user}),
          edit: (user) => this.usersService.updateUser({ user }),
        },
      },
    });
  }

}