Adding support for nested types, array and dates!

This commit is contained in:
2023-01-19 18:39:51 +01:00
parent aa4399ea20
commit 70d5a6e752
9 changed files with 246 additions and 23 deletions

View File

@@ -1,11 +1,11 @@
<div>
<form [formGroup]="form" (ngSubmit)="onSubmit(model)">
<form cForm [formGroup]="form" (ngSubmit)="onSubmit(model)">
<span class="col col-form-label" *ngIf="loading$ | async">Loading...</span>
<formly-form [form]="form" [fields]="fields" [model]="model"></formly-form>
<button color="primary" type="submit" class="btn btn-default">
<button cButton color="primary">
{{ this.isCreateForm() ? "Create" : "Update" }}
</button>
<button *ngIf="!this.isCreateForm()" (click)="onDelete()" color="danger" type="" class="btn btn-default">
<button cButton *ngIf="!this.isCreateForm()" (click)="onDelete()" color="danger">
Delete
</button>
</form>

View File

@@ -1,8 +1,6 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
//import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import { HttpClientModule } from "@angular/common/http";
import { FormsModule, ReactiveFormsModule} from '@angular/forms';
@@ -11,17 +9,23 @@ import { FormlyBootstrapModule } from '@ngx-formly/bootstrap';
import { CardComponent } from './card/card.component';
import { ListComponent } from './list/list.component';
import { ObjectTypeComponent } from "./object.type";
import {ApiService, CrudService} from "./crud.service";
import {NgbModule} from "@ng-bootstrap/ng-bootstrap";
import {JsonschemasService} from "./jsonschemas.service";
import { ArrayTypeComponent } from "./types/array.type";
import { ObjectTypeComponent } from "./types/object.type";
import { DatetimeTypeComponent } from "./types/datetime.type";
import { ApiService, CrudService } from "./crud.service";
import { NgbModule} from "@ng-bootstrap/ng-bootstrap";
import { JsonschemasService } from "./jsonschemas.service";
import { MultiSchemaTypeComponent } from "./types/multischema.type";
@NgModule({
declarations: [
CardComponent,
ListComponent,
ObjectTypeComponent
ObjectTypeComponent,
DatetimeTypeComponent,
ArrayTypeComponent,
MultiSchemaTypeComponent
],
providers: [ JsonschemasService, ApiService, CrudService ],
imports: [
@@ -34,6 +38,9 @@ import {JsonschemasService} from "./jsonschemas.service";
FormlyModule.forRoot({
types: [
{ name: 'object', component: ObjectTypeComponent },
{ name: 'datetime', component: DatetimeTypeComponent },
{ name: 'array', component: ArrayTypeComponent },
{ name: 'multischema', component: MultiSchemaTypeComponent },
]
}),
FormlyBootstrapModule

View File

@@ -32,15 +32,35 @@ export class JsonschemasService {
for (let prop_name in resource.properties) {
let prop = resource.properties[prop_name];
if (this.is_reference(prop)) {
let subresourceName = this.get_reference_name(prop);
resource.components.schemas[subresourceName] = this.buildResource(subresourceName);
if (prop_name === '_id') {
delete resource.properties[prop_name]
} else if (this.is_reference(prop)) {
this.resolveReference(resource, prop);
} else if (prop.hasOwnProperty('oneOf')) {
for (let i in prop.oneOf) {
this.resolveReference(resource, prop.oneOf[i]);
}
} else if (prop.hasOwnProperty('items') && this.is_reference(prop.items)) {
this.resolveReference(resource, prop.items);
} else if (prop.format === 'date-time') {
prop.type = "datetime";
}
}
return resource;
}
resolveReference(resource: any, prop_reference: any) {
let subresourceName = this.get_reference_name(prop_reference);
let subresource = this.buildResource(subresourceName);
resource.components.schemas[subresourceName] = subresource;
for (let subsubresourceName in subresource.components.schemas) {
if (! resource.components.schemas.hasOwnProperty(subsubresourceName)) {
resource.components.schemas[subsubresourceName] = subresource.components.schemas[subsubresourceName];
}
}
}
getCreateResource(resourceName: string): Observable<Schema> {
return new Observable<Schema>((observer) => {
this.getSchemas().subscribe(() => {
@@ -75,6 +95,10 @@ export class JsonschemasService {
return prop.hasOwnProperty('$ref');
}
private is_union(prop: any) {
return prop.hasOwnProperty('oneOf');
}
private get_reference_name(prop: any) {
return prop['$ref'].substring(prop['$ref'].lastIndexOf('/')+1);
}

View File

@@ -0,0 +1,36 @@
import { Component } from '@angular/core';
import { FieldArrayType } from '@ngx-formly/core';
@Component({
selector: 'formly-array-type',
template: `
<div class="mb-3">
<label *ngIf="props.label" class="form-label">{{ props.label }}</label>
<p *ngIf="props.description">{{ props.description }}</p>
<div class="d-flex flex-row-reverse">
<button class="btn btn-primary" type="button" (click)="add()">+</button>
</div>
<div class="alert alert-danger" role="alert" *ngIf="showError && formControl.errors">
<formly-validation-message [field]="field"></formly-validation-message>
</div>
<div *ngFor="let field of field.fieldGroup; let i = index" class="row align-items-start">
<formly-field class="col" [field]="field"></formly-field>
<div *ngIf="field.props!['removable'] !== false" class="col-2 text-right">
<button class="btn btn-danger" type="button" (click)="remove(i)">-</button>
</div>
</div>
</div>
`,
})
export class ArrayTypeComponent extends FieldArrayType {
constructor() {
super();
}
}
/** Copyright 2021 Formly. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://github.com/ngx-formly/ngx-formly/blob/main/LICENSE */

View File

@@ -0,0 +1,89 @@
import { Component, ElementRef, OnInit, ViewChild} from '@angular/core';
import { formatDate } from "@angular/common";
import { NgbDateStruct, NgbTimeStruct } from '@ng-bootstrap/ng-bootstrap';
import { FieldType, FieldTypeConfig } from '@ngx-formly/core';
@Component({
selector: 'app-form-datepicker-type',
template: `
<label *ngIf="props.label && props['hideLabel'] !== true" [attr.for]="id"
class="form-label">{{ props.label }}
<span *ngIf="props.required && props['hideRequiredMarker'] !== true" aria-hidden="true">*</span>
</label>
<div class="input-group" *ngIf="! this.field.props.readonly">
<input type="text"
[formControl]="formControl"
[formlyAttributes]="field"
[class.is-invalid]="showError"
/>
<input
class="form-control"
placeholder="yyyy-mm-dd"
name="dp"
[(ngModel)]="date"
(ngModelChange)="changeDatetime($event)"
ngbDatepicker
#d="ngbDatepicker"
/>
<button class="btn btn-outline-secondary bi bi-calendar3" (click)="d.toggle()" type="button"></button>
<ngb-timepicker
(ngModelChange)="changeDatetime($event)"
[(ngModel)]="time"
[seconds]="true">
</ngb-timepicker>
</div>
<div class="input-group" *ngIf="this.field.props.readonly">
<input class="form-control" value="{{ this.datetime.toLocaleString() }}" disabled=""/>
</div>
`,
})
export class DatetimeTypeComponent extends FieldType<FieldTypeConfig> implements OnInit
{
public time : NgbTimeStruct = { hour: 12, minute: 0, second: 0 }
public date : NgbDateStruct = { year: 2023, month: 1, day: 9 }
public datetime : Date = new Date()
constructor() {
super();
}
ngOnInit() {
this.formControl.valueChanges.subscribe(value => {
this.datetime = new Date(value)
this.date = this.getDateStruct(this.datetime);
this.time = this.getTimeStruct(this.datetime);
})
}
getDateStruct(d: Date) {
return {
year: d.getFullYear(),
month: d.getMonth() + 1,
day: d.getDate(),
}
}
getTimeStruct(d: Date) {
return {
hour: d.getHours(),
minute: d.getMinutes(),
second: d.getSeconds(),
}
}
changeDatetime(event: any) {
this.datetime.setFullYear(this.date.year)
this.datetime.setMonth(this.date.month - 1)
this.datetime.setDate(this.date.day)
this.datetime.setHours(this.time.hour)
this.datetime.setMinutes(this.time.minute)
this.datetime.setSeconds(this.time.second)
this.formControl.setValue(
formatDate(this.datetime, 'YYYY-MM-ddTHH:mm:ss.SSS', 'EN_US', 'CET')
)
}
}

View File

@@ -0,0 +1,38 @@
import {Component, OnInit} from '@angular/core';
import { FieldType } from '@ngx-formly/core';
import {Observable} from "rxjs";
@Component({
selector: 'formly-multi-schema-type',
template: `
<div class="card mb-3">
<div class="card-body">
<label *ngIf="props.label" class="form-label">{{ props.label }}</label>
<p *ngIf="props.description">{{ props.description }}</p>
<div class="alert alert-danger" role="alert" *ngIf="showError && formControl.errors">
<formly-validation-message [field]="field"></formly-validation-message>
</div>
<formly-field *ngFor="let f of field.fieldGroup" [field]="f"></formly-field>
</div>
</div>
`,
})
export class MultiSchemaTypeComponent extends FieldType implements OnInit {
ngOnInit() {
let f = this.field
f.fieldGroup![0].props!.options!.forEach(function (option) {
option.label = f.fieldGroup![1].fieldGroup![option.value].props!.label;
f.fieldGroup![1].fieldGroup![option.value].props!.label = "";
});
f.fieldGroup![1].fieldGroup!.forEach(function (field) {
//field.fieldGroup![0].hide = true;
});
}
}
/** Copyright 2021 Formly. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at https://github.com/ngx-formly/ngx-formly/blob/main/LICENSE */