Initial commit
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
import { Component, inject, signal } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatDatepickerModule } from '@angular/material/datepicker';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { ApiService } from '../../core/services/api.service';
|
||||
import { CrudConfig, FieldConfig, SelectOption } from './crud-config';
|
||||
|
||||
interface DialogData { config: CrudConfig; entity: Record<string, any> | null; }
|
||||
|
||||
@Component({
|
||||
selector: 'app-crud-form-dialog',
|
||||
imports: [
|
||||
ReactiveFormsModule, MatDialogModule, MatFormFieldModule, MatInputModule, MatSelectModule,
|
||||
MatDatepickerModule, MatButtonModule, MatIconModule,
|
||||
],
|
||||
templateUrl: './crud-form-dialog.component.html',
|
||||
styleUrl: './crud-form-dialog.component.scss',
|
||||
})
|
||||
export class CrudFormDialogComponent {
|
||||
private fb = inject(FormBuilder);
|
||||
private api = inject(ApiService);
|
||||
readonly data = inject<DialogData>(MAT_DIALOG_DATA);
|
||||
private ref = inject(MatDialogRef<CrudFormDialogComponent>);
|
||||
|
||||
readonly isEdit = !!this.data.entity;
|
||||
readonly form: FormGroup;
|
||||
readonly options = signal<Record<string, SelectOption[]>>({});
|
||||
|
||||
constructor() {
|
||||
const group: Record<string, any> = {};
|
||||
for (const f of this.data.config.fields) {
|
||||
const validators = [];
|
||||
if (f.required) validators.push(Validators.required);
|
||||
if (f.min != null) validators.push(Validators.min(f.min));
|
||||
if (f.max != null) validators.push(Validators.max(f.max));
|
||||
if (f.maxLength != null) validators.push(Validators.maxLength(f.maxLength));
|
||||
group[f.key] = [this.initialValue(f), validators];
|
||||
}
|
||||
this.form = this.fb.group(group);
|
||||
|
||||
// Load lookup-backed select options.
|
||||
for (const f of this.data.config.fields) {
|
||||
if (f.options) {
|
||||
this.options.update((o) => ({ ...o, [f.key]: f.options! }));
|
||||
} else if (f.lookup) {
|
||||
this.api.lookup(f.lookup).subscribe((items) => {
|
||||
this.options.update((o) => ({ ...o, [f.key]: items.map((i) => ({ value: i.id, label: i.name })) }));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private initialValue(f: FieldConfig): any {
|
||||
const raw = this.data.entity?.[f.key];
|
||||
if (raw == null || raw === '') return f.type === 'select' ? null : null;
|
||||
if (f.type === 'date') return new Date(raw);
|
||||
if (f.type === 'datetime') return this.toLocalInput(new Date(raw));
|
||||
return raw;
|
||||
}
|
||||
|
||||
private toLocalInput(d: Date): string {
|
||||
const p = (n: number) => String(n).padStart(2, '0');
|
||||
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}T${p(d.getHours())}:${p(d.getMinutes())}`;
|
||||
}
|
||||
|
||||
private toDateOnly(d: Date): string {
|
||||
const p = (n: number) => String(n).padStart(2, '0');
|
||||
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}`;
|
||||
}
|
||||
|
||||
optionsFor(key: string): SelectOption[] {
|
||||
return this.options()[key] ?? [];
|
||||
}
|
||||
|
||||
save() {
|
||||
if (this.form.invalid) { this.form.markAllAsTouched(); return; }
|
||||
const payload: Record<string, any> = {};
|
||||
for (const f of this.data.config.fields) {
|
||||
let v = this.form.value[f.key];
|
||||
if (v === '' || v === undefined) v = null;
|
||||
if (v != null && f.type === 'date' && v instanceof Date) v = this.toDateOnly(v);
|
||||
if (v != null && f.type === 'number') v = Number(v);
|
||||
payload[f.key] = v;
|
||||
}
|
||||
this.ref.close(payload);
|
||||
}
|
||||
|
||||
cancel() { this.ref.close(null); }
|
||||
}
|
||||
Reference in New Issue
Block a user