Browse Source

Allow users to edit the field after they create it in the field wizard. They can also go back and keep adding fields and editing them until they are done with that schema.

pull/328/head
Alexander Van Dyke 7 years ago
parent
commit
6ec2dadd40
  1. 155
      src/Squidex/app/features/schemas/pages/schema/field-wizard.component.html
  2. 173
      src/Squidex/app/features/schemas/pages/schema/field-wizard.component.ts
  3. 5
      src/Squidex/app/features/schemas/pages/schema/field.component.ts
  4. 26
      src/Squidex/app/features/schemas/pages/schema/forms/field-form-common.component.ts

155
src/Squidex/app/features/schemas/pages/schema/field-wizard.component.html

@ -1,68 +1,111 @@
<form [formGroup]="addFieldForm.form" (ngSubmit)="addField(false)">
<sqx-modal-dialog (closed)="complete()" large="true">
<ng-container title>
<ng-container *ngIf="parent; else noParent">
Add Nested Field
</ng-container>
<ng-template #noParent>
Add Field
</ng-template>
<sqx-modal-dialog (closed)="complete()" large="true">
<ng-container title>
<ng-container *ngIf="parent; else noParent">
Add Nested Field
</ng-container>
<ng-container content>
<sqx-form-error [error]="addFieldForm.error | async"></sqx-form-error>
<div class="form-group">
<div class="row">
<div class="col-4 type" *ngFor="let fieldType of fieldTypes">
<label>
<input type="radio" class="radio-input" formControlName="type" value="{{fieldType.type}}" />
<div class="row no-gutters">
<div class="col col-auto">
<div class="type-icon" [class.active]="addFieldForm.form.controls['type'].value === fieldType.type">
<i class="icon-type-{{fieldType.type}}"></i>
<ng-template #noParent>
{{step === 1 ? 'Add' : 'Edit'}} Field
</ng-template>
</ng-container>
<ng-container content>
<ng-container *ngIf="step === 1">
<form [formGroup]="addFieldForm.form" (ngSubmit)="addField(false)">
<sqx-form-error [error]="addFieldForm.error | async"></sqx-form-error>
<div class="form-group">
<div class="row">
<div class="col-4 type" *ngFor="let fieldType of fieldTypes">
<label>
<input type="radio" class="radio-input" formControlName="type" value="{{fieldType.type}}" />
<div class="row no-gutters">
<div class="col col-auto">
<div class="type-icon" [class.active]="addFieldForm.form.controls['type'].value === fieldType.type">
<i class="icon-type-{{fieldType.type}}"></i>
</div>
</div>
<div class="col-lg">
<div class="type-title">{{fieldType.type}}</div>
<div class="type-text text-muted">{{fieldType.description}}</div>
</div>
</div>
<div class="col-lg">
<div class="type-title">{{fieldType.type}}</div>
<div class="type-text text-muted">{{fieldType.description}}</div>
</div>
</div>
</label>
</label>
</div>
</div>
</div>
</div>
<div class="form-group">
<sqx-control-errors for="name" submitOnly="true" [submitted]="addFieldForm.submitted | async"></sqx-control-errors>
<input type="text" class="form-control" formControlName="name" maxlength="40" #nameInput placeholder="Enter field name" sqxFocusOnInit />
</div>
<div class="form-group" *ngIf="!parent">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="isLocalizable" formControlName="isLocalizable" />
<label class="form-check-label" for="isLocalizable">
Localizable
</label>
<div class="form-group">
<sqx-control-errors for="name" submitOnly="true" [submitted]="addFieldForm.submitted | async"></sqx-control-errors>
<input type="text" class="form-control" formControlName="name" maxlength="40" #nameInput
placeholder="Enter field name" sqxFocusOnInit />
</div>
<small class="form-text text-muted">
You can the field as localizable. It means that is dependent on the language, for example a city name.
</small>
</div>
<div class="form-group" *ngIf="!parent">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="isLocalizable" formControlName="isLocalizable" />
<label class="form-check-label" for="isLocalizable">
Localizable
</label>
</div>
<small class="form-text text-muted">
You can the field as localizable. It means that is dependent on the language, for example a
city name.
</small>
</div>
</form>
</ng-container>
<ng-container footer>
<button type="reset" class="float-left btn btn-secondary" (click)="complete()">Cancel</button>
<div class="table-items-row-details" *ngIf="step === 2">
<form [formGroup]="editForm.form" (ngSubmit)="save()">
<div class="table-items-row-details-tabs clearfix">
<ul class="nav nav-tabs2">
<li class="nav-item">
<a class="nav-link" (click)="selectTab(0)" [class.active]="selectedTab === 0">Common</a>
</li>
<li class="nav-item">
<a class="nav-link" (click)="selectTab(1)" [class.active]="selectedTab === 1">Validation</a>
</li>
<li class="nav-item">
<a class="nav-link" (click)="selectTab(2)" [class.active]="selectedTab === 2">Editing</a>
</li>
</ul>
</div>
<div class="float-right">
<button class="btn btn-success mr-1" (click)="addField(false)">Create and close</button>
<button class="btn btn-success" (click)="addField(true)">Create and new field</button>
</div>
</ng-container>
</sqx-modal-dialog>
</form>
<ng-container *ngIf="patternsState.patterns | async; let patterns">
<div class="table-items-row-details-tab" [class.hidden]="selectedTab !== 0">
<sqx-field-form-common [editForm]="editForm.form" [editFormSubmitted]="editForm.submitted | async"
[field]="field"></sqx-field-form-common>
</div>
<div class="table-items-row-details-tab" [class.hidden]="selectedTab !== 1">
<sqx-field-form-validation [patterns]="patterns" [editForm]="editForm.form" [field]="field"></sqx-field-form-validation>
</div>
<div class="table-items-row-details-tab" [class.hidden]="selectedTab !== 2">
<sqx-field-form-ui [editForm]="editForm.form" [field]="field"></sqx-field-form-ui>
</div>
</ng-container>
</form>
</div>
</ng-container>
<ng-container footer>
<button type="reset" class="float-left btn btn-secondary" (click)="complete()">Cancel</button>
<div class="float-right" *ngIf="step === 1">
<button class="btn btn-success mr-1" (click)="addField(false, false)">Create and close</button>
<button class="btn btn-success mr-1" (click)="addField(true, false)">Create and new field</button>
<button class="btn btn-success" (click)="addField(false, true)">Create and edit field</button>
</div>
<div class="float-right" *ngIf="step === 2">
<button class="btn btn-success mr-1" (click)="save(true)">Save and add field</button>
<button (click)="save()" class="btn btn-primary ml-1">Save and close</button>
</div>
</ng-container>
</sqx-modal-dialog>

173
src/Squidex/app/features/schemas/pages/schema/field-wizard.component.ts

@ -5,75 +5,142 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
import { FormBuilder } from '@angular/forms';
import {
AddFieldForm,
fieldTypes,
RootFieldDto,
SchemaDetailsDto,
SchemasState,
Types
} from '@app/shared';
Component,
ElementRef,
EventEmitter,
Input,
OnInit,
Output,
ViewChild
} from "@angular/core";
import { FormBuilder } from "@angular/forms";
import {
AddFieldForm,
AppPatternDto,
createProperties,
EditFieldForm,
FieldDto,
fieldTypes,
ImmutableArray,
PatternsState,
RootFieldDto,
SchemaDetailsDto,
SchemasState,
Types,
UpdateFieldDto
} from "@app/shared";
import { onErrorResumeNext } from "rxjs/operators";
@Component({
selector: 'sqx-field-wizard',
styleUrls: ['./field-wizard.component.scss'],
templateUrl: './field-wizard.component.html'
selector: "sqx-field-wizard",
styleUrls: ["./field-wizard.component.scss"],
templateUrl: "./field-wizard.component.html"
})
export class FieldWizardComponent implements OnInit {
@ViewChild('nameInput')
public nameInput: ElementRef;
@ViewChild("nameInput")
public nameInput: ElementRef;
@Input()
public schema: SchemaDetailsDto;
@Input()
public schema: SchemaDetailsDto;
@Input()
public parent: RootFieldDto;
@Input()
public parent: RootFieldDto;
@Output()
public completed = new EventEmitter();
@Output()
public completed = new EventEmitter();
public fieldTypes = fieldTypes;
public fieldTypes = fieldTypes;
public addFieldForm = new AddFieldForm(this.formBuilder);
public editForm = new EditFieldForm(this.formBuilder);
public field: FieldDto;
public isEditing = false;
public selectedTab = 0;
public patterns: ImmutableArray<AppPatternDto>;
public addFieldForm = new AddFieldForm(this.formBuilder);
public step = 1;
constructor(
private readonly formBuilder: FormBuilder,
private readonly schemasState: SchemasState
) {
constructor(
private readonly formBuilder: FormBuilder,
private readonly schemasState: SchemasState,
public readonly patternsState: PatternsState
) {}
public ngOnInit() {
if (this.parent) {
this.fieldTypes = this.fieldTypes.filter(x => x.type !== "Array");
}
this.patternsState
.load()
.pipe(onErrorResumeNext())
.subscribe();
}
public complete() {
this.completed.emit();
}
public addField(next: boolean, edit: boolean) {
const value = this.addFieldForm.submit();
public ngOnInit() {
if (this.parent) {
this.fieldTypes = this.fieldTypes.filter(x => x.type !== 'Array');
if (value) {
this.schemasState.addField(this.schema, value, this.parent).subscribe(
dto => {
this.field = dto;
this.addFieldForm.submitCompleted({ type: fieldTypes[0].type });
if (next) {
if (Types.isFunction(this.nameInput.nativeElement.focus)) {
this.nameInput.nativeElement.focus();
}
} else if (edit) {
this.selectTab(0);
this.step++;
} else {
this.complete();
}
},
error => {
this.addFieldForm.submitFailed(error);
}
);
}
}
public complete() {
this.completed.emit();
}
public selectTab(tab: number) {
this.selectedTab = tab;
}
public addField(next: boolean) {
const value = this.addFieldForm.submit();
if (value) {
this.schemasState.addField(this.schema, value, this.parent)
.subscribe(dto => {
this.addFieldForm.submitCompleted({ type: fieldTypes[0].type });
if (next) {
if (Types.isFunction(this.nameInput.nativeElement.focus)) {
this.nameInput.nativeElement.focus();
}
} else {
this.complete();
}
}, error => {
this.addFieldForm.submitFailed(error);
});
}
public save(addNew: boolean) {
const value = this.editForm.submit();
if (value) {
const properties = createProperties(
this.field.properties["fieldType"],
value
);
this.schemasState
.updateField(
this.schema,
this.field as RootFieldDto,
new UpdateFieldDto(properties)
)
.subscribe(
() => {
this.isEditing = false;
this.editForm.submitCompleted();
if (addNew) {
this.step--;
} else {
this.complete();
}
},
error => {
this.editForm.submitFailed(error);
}
);
}
}
}

5
src/Squidex/app/features/schemas/pages/schema/field.component.ts

@ -71,6 +71,11 @@ export class FieldComponent implements OnInit {
public toggleEditing() {
this.isEditing = !this.isEditing;
// Reload the defaults if they were set in the wizard
if (this.isEditing) {
this.editForm.load(this.field.properties);
}
}
public selectTab(tab: number) {

26
src/Squidex/app/features/schemas/pages/schema/forms/field-form-common.component.ts

@ -5,8 +5,8 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Component, Input } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { Component, Input, OnChanges } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { FieldDto } from '@app/shared';
@ -15,7 +15,7 @@ import { FieldDto } from '@app/shared';
styleUrls: ['field-form-common.component.scss'],
templateUrl: 'field-form-common.component.html'
})
export class FieldFormCommonComponent {
export class FieldFormCommonComponent implements OnChanges {
@Input()
public editForm: FormGroup;
@ -27,4 +27,24 @@ export class FieldFormCommonComponent {
@Input()
public field: FieldDto;
public ngOnChanges() {
this.editForm.setControl('isRequired',
new FormControl(this.field.properties.isRequired));
this.editForm.setControl('isListField',
new FormControl(this.field.properties.isListField));
this.editForm.setControl('editorUrl',
new FormControl(this.field.properties.editorUrl));
this.editForm.setControl('hints',
new FormControl(this.field.properties.hints));
this.editForm.setControl('placeholder',
new FormControl(this.field.properties.placeholder));
this.editForm.setControl('label',
new FormControl(this.field.properties.label));
}
}
Loading…
Cancel
Save