src/app/core/form-dialog/dialog-buttons/dialog-buttons.component.ts

Metadata

Relationships

Depends on

Index

Properties
Methods
Inputs
Outputs

Constructor

constructor()

Inputs

entity
Type : E
Required :  true
form
Type : EntityForm<E>
Required :  true

Outputs

closeView
Type : any

Methods

cancel
cancel()
Returns : void
close
close(result?: any)
Parameters :
Name Type Optional
result any Yes
Returns : void
onAction
onAction(action: string)
Parameters :
Name Type Optional
action string No
Returns : void
Async save
save()
Returns : any

Properties

detailsRoute
Type : unknown
Default value : computed(() => { const entity = this.entity(); if (entity.isNew) { return undefined; } const route = getEntityRuntimeRoute(entity.getConstructor()); const detailsPath = `${route.replace(/^\//, "")}/:id`; if (route && this.router.config.some((r) => r.path === detailsPath)) { return route + "/" + entity.getId(true); } return undefined; })
Protected viewContext
Type : unknown
Default value : inject(ViewComponentContext, { optional: true })
import {
  Component,
  inject,
  ChangeDetectionStrategy,
  input,
  output,
  computed,
  effect,
} from "@angular/core";
import { MatButtonModule } from "@angular/material/button";
import { Angulartics2Module } from "angulartics2";
import { MatDialogModule, MatDialogRef } from "@angular/material/dialog";
import { Entity } from "../../entity/model/entity";
import { InvalidFormFieldError } from "../../common-components/entity-form/invalid-form-field.error";
import { EntityFormService } from "../../common-components/entity-form/entity-form.service";
import { EntityForm } from "#src/app/core/common-components/entity-form/entity-form";
import { AlertService } from "../../alerts/alert.service";
import { MatMenuModule } from "@angular/material/menu";
import { FontAwesomeModule } from "@fortawesome/angular-fontawesome";
import { Router, RouterLink } from "@angular/router";
import { EntityAbility } from "../../permissions/ability/entity-ability";
import { UnsavedChangesService } from "../../entity-details/form/unsaved-changes.service";
import { EntityActionsMenuComponent } from "../../entity-details/entity-actions-menu/entity-actions-menu.component";
import { ViewComponentContext } from "../../ui/abstract-view/view-component-context";
import { getEntityRuntimeRoute } from "../../entity/entity-config.service";

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: "app-dialog-buttons",
  imports: [
    MatButtonModule,
    Angulartics2Module,
    MatDialogModule,
    MatMenuModule,
    FontAwesomeModule,
    RouterLink,
    EntityActionsMenuComponent,
  ],
  templateUrl: "./dialog-buttons.component.html",
  styleUrls: ["./dialog-buttons.component.scss"],
})
export class DialogButtonsComponent<E extends Entity> {
  private entityFormService = inject(EntityFormService);
  private dialog = inject<MatDialogRef<any>>(MatDialogRef, { optional: true });
  private alertService = inject(AlertService);
  private router = inject(Router);
  private ability = inject(EntityAbility);
  private unsavedChanges = inject(UnsavedChangesService);

  protected viewContext = inject(ViewComponentContext, { optional: true });

  entity = input.required<E>();
  form = input.required<EntityForm<E>>();
  closeView = output<any>();

  detailsRoute = computed(() => {
    const entity = this.entity();
    if (entity.isNew) {
      return undefined;
    }
    const route = getEntityRuntimeRoute(entity.getConstructor());
    const detailsPath = `${route.replace(/^\//, "")}/:id`;
    if (route && this.router.config.some((r) => r.path === detailsPath)) {
      return route + "/" + entity.getId(true);
    }
    return undefined;
  });

  constructor() {
    if (this.dialog) {
      this.initDialogSettings();
    }

    // Handle permissions check when entity changes
    effect(() => {
      const entity = this.entity();
      const form = this.form();
      if (!entity.isNew) {
        if (this.ability.cannot("update", entity)) {
          form.formGroup.disable();
        }
      }
    });
  }

  private initDialogSettings() {
    this.dialog.disableClose = true;
    this.dialog.backdropClick().subscribe(() =>
      // only consider this dialog's own form, so a dirty view underneath the dialog
      // does not trigger a discard prompt for changes unrelated to this dialog
      this.unsavedChanges.checkUnsavedChanges(this.form()).then((confirmed) => {
        if (confirmed) {
          this.dialog.close();
        }
      }),
    );
  }

  async save() {
    this.entityFormService
      .saveChanges(this.form(), this.entity())
      .then((res) => {
        // Attachments are only saved once form is disabled
        this.form().formGroup.disable();
        this.form().formGroup.markAsPristine();
        this.close(res);
      })
      .catch((err) => {
        if (!(err instanceof InvalidFormFieldError)) {
          this.alertService.addDanger(err.message);
        }
      });
  }

  cancel() {
    // discard this form's unsaved changes
    this.unsavedChanges.setUnsavedChanges(this.form(), false);
    this.close();
  }

  close(result?: any) {
    this.dialog?.close(result);
    this.closeView.emit(result);
  }

  onAction(action: string) {
    if (action === "delete") {
      this.close();
    }
  }
}
<button
  mat-raised-button
  color="accent"
  (click)="save()"
  angulartics2On="click"
  [angularticsCategory]="entity()?.getType()"
  angularticsAction="form_popup_save"
  i18n="Form save button"
>
  Save
</button>

@if (viewContext?.isDialog) {
  <button
    mat-stroked-button
    (click)="cancel()"
    angulartics2On="click"
    [angularticsCategory]="entity()?.getType()"
    angularticsAction="form_popup_cancel"
    i18n="Form cancel button"
  >
    Cancel
  </button>
}

@if (detailsRoute() && viewContext?.isDialog) {
  <button
    mat-raised-button
    [routerLink]="detailsRoute()"
    mat-dialog-close
    [disabled]="form().formGroup.disabled"
    i18n="Form button to navigate to details page of entity"
  >
    Go to details
  </button>
}

<!-- inline content projected immediately before the context menu (e.g. the
     change-history button), so it sits right next to the "⋮" trigger -->
<ng-content select="[beforeContextMenu]"></ng-content>

<app-entity-actions-menu
  [entity]="entity()"
  (actionTriggered)="onAction($event)"
>
  <ng-content></ng-content>
</app-entity-actions-menu>

./dialog-buttons.component.scss

:host {
  display: flex;
  align-items: center;
}
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""