Browse Source

Unset value (#551)

* Unset value

* Unset buttons fixed.
pull/561/head
Sebastian Stehle 5 years ago
committed by GitHub
parent
commit
461f356d40
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 58
      frontend/app/features/content/pages/content/content-field.component.html
  2. 16
      frontend/app/features/content/pages/content/content-field.component.scss
  3. 1
      frontend/app/features/content/shared/forms/array-editor.component.html
  4. 3
      frontend/app/features/content/shared/forms/array-editor.component.ts
  5. 1
      frontend/app/features/content/shared/forms/array-item.component.html
  6. 3
      frontend/app/features/content/shared/forms/array-item.component.ts
  7. 2
      frontend/app/features/content/shared/forms/array-section.component.html
  8. 3
      frontend/app/features/content/shared/forms/array-section.component.ts
  9. 9
      frontend/app/features/content/shared/forms/field-editor.component.html
  10. 12
      frontend/app/features/content/shared/forms/field-editor.component.scss
  11. 21
      frontend/app/features/content/shared/forms/field-editor.component.ts
  12. 26
      frontend/app/framework/angular/forms/string-form-control.spec.ts
  13. 39
      frontend/app/framework/angular/forms/string-form-control.ts
  14. 7
      frontend/app/framework/angular/modals/tooltip.directive.ts
  15. 1
      frontend/app/framework/declarations.ts
  16. 14
      frontend/app/shared/state/contents.forms.ts

58
frontend/app/features/content/pages/content/content-field.component.html

@ -1,27 +1,30 @@
<div class="row no-gutters" [class.compare]="formModelCompare">
<div [class.col-12]="!formModelCompare" [class.col-6]="formModelCompare">
<div class="table-items-row" [class.field-invalid]="isInvalid | async" *ngIf="!(formModel.hiddenChanges | async)">
<div class="languages-buttons">
<button *ngIf="canTranslate" type="button" class="btn btn-text-secondary btn-sm mr-1" (click)="translate()" title="Autotranslate from master language">
<i class="icon-translate"></i>
</button>
<sqx-field-languages
[field]="formModel.field"
(languageChange)="languageChange.emit($event)"
[language]="language"
[languages]="languages"
[showAllControls]="showAllControls"
(showAllControlsChange)="changeShowAllControls($event)">
</sqx-field-languages>
<div class="languages-container">
<div class="languages-buttons">
<button *ngIf="canTranslate" type="button" class="btn btn-text-secondary btn-sm mr-1" (click)="translate()" title="Autotranslate from master language">
<i class="icon-translate"></i>
</button>
<sqx-field-languages
[field]="formModel.field"
(languageChange)="languageChange.emit($event)"
[language]="language"
[languages]="languages"
[showAllControls]="showAllControls"
(showAllControlsChange)="changeShowAllControls($event)">
</sqx-field-languages>
</div>
</div>
<ng-container *ngIf="showAllControls; else singleControl">
<div class="form-group" *ngFor="let language of formModel; trackBy: trackByLanguage">
<div class="form-group" *ngFor="let language of languages">
<sqx-field-editor
[canUnset]="true"
[form]="form"
[formContext]="formContext"
[formModel="formModel.getField(language.iso2Code)"
[formModel]="formModel.get(language)"
[language]="language"
[languages]="languages"
[displaySuffix]="prefix(language)">
@ -31,6 +34,7 @@
<ng-template #singleControl>
<sqx-field-editor
[canUnset]="true"
[form]="form"
[formContext]="formContext"
[formModel]="getControl()"
@ -47,23 +51,25 @@
</button>
<div class="table-items-row" *ngIf="!(formModelCompare!.hiddenChanges | async)">
<div class="languages-buttons">
<sqx-field-languages
[field]="formModelCompare!.field"
(languageChange)="languageChange.emit($event)"
[language]="language"
[languages]="languages"
[showAllControls]="showAllControls"
(showAllControlsChange)="changeShowAllControls($event)">
</sqx-field-languages>
<div class="languages-container">
<div class="languages-buttons-compare">
<sqx-field-languages
[field]="formModelCompare!.field"
(languageChange)="languageChange.emit($event)"
[language]="language"
[languages]="languages"
[showAllControls]="showAllControls"
(showAllControlsChange)="changeShowAllControls($event)">
</sqx-field-languages>
</div>
</div>
<ng-container *ngIf="showAllControls; else singleControlCompare">
<div class="form-group" *ngFor="let language of languages; trackBy: trackByLanguage">
<div class="form-group" *ngFor="let language of languages">
<sqx-field-editor
[form]="formCompare"
[formContext]="formContext"
[formModel="formModelCompare.getField(language.iso2Code)"
[formModel]="formModelCompare.get(language)"
[language]="language"
[languages]="languages"
[displaySuffix]="prefix(language)">

16
frontend/app/features/content/pages/content/content-field.component.scss

@ -3,8 +3,20 @@
position: relative;
}
.languages-buttons {
@include absolute(.25rem, 1.25rem);
.languages {
&-container {
position: relative;
}
&-buttons {
@include absolute(-.5rem, 2rem);
z-index: 1000;
}
&-buttons-compare {
@include absolute(-.5rem, 0);
z-index: 1000;
}
}
.col-6 {

1
frontend/app/features/content/shared/forms/array-editor.component.html

@ -8,6 +8,7 @@
cdkDrag
cdkDragLockAxis="y">
<sqx-array-item
[canUnset]="canUnset"
[form]="form"
[formContext]="formContext"
[formModel]="itemForm"

3
frontend/app/features/content/shared/forms/array-editor.component.ts

@ -26,6 +26,9 @@ export class ArrayEditorComponent {
@Input()
public formModel: FieldArrayForm;
@Input()
public canUnset: boolean;
@Input()
public language: AppLanguageDto;

1
frontend/app/features/content/shared/forms/array-item.component.html

@ -45,6 +45,7 @@
<div class="card-body" [class.hidden]="isCollapsed">
<div class="form-group" *ngFor="let section of formModel.sections">
<sqx-array-section
[canUnset]="canUnset"
[form]="form"
[formContext]="formContext"
[formSection]="section"

3
frontend/app/features/content/shared/forms/array-item.component.ts

@ -37,6 +37,9 @@ export class ArrayItemComponent implements OnChanges {
@Input()
public formModel: FieldArrayItemForm;
@Input()
public canUnset: boolean;
@Input()
public isFirst = false;

2
frontend/app/features/content/shared/forms/array-section.component.html

@ -9,9 +9,11 @@
<div class="form-group" *ngFor="let child of formSection.fields; trackBy: trackByField">
<sqx-field-editor *ngIf="!(child.hiddenChanges | async)"
[canUnset]="canUnset"
[form]="form"
[formContext]="formContext"
[formModel]="child"
[canUnset]="canUnset"
[language]="language"
[languages]="languages">
</sqx-field-editor>

3
frontend/app/features/content/shared/forms/array-section.component.ts

@ -31,6 +31,9 @@ export class ArraySectionComponent {
@Input()
public languages: ReadonlyArray<AppLanguageDto>;
@Input()
public canUnset: boolean;
@ViewChildren(FieldEditorComponent)
public editors: QueryList<FieldEditorComponent>;

9
frontend/app/features/content/shared/forms/field-editor.component.html

@ -1,4 +1,4 @@
<div *ngIf="formModel">
<div class="field" *ngIf="formModel">
<label>
{{field.displayName}} {{displaySuffix}} <span class="field-required" [class.hidden]="!field.properties.isRequired">*</span>
</label>
@ -20,6 +20,7 @@
<ng-container [ngSwitch]="field.properties.fieldType">
<ng-container *ngSwitchCase="'Array'">
<sqx-array-editor
[canUnset]="canUnset"
[formModel]="formModel"
[formContext]="formContext"
[language]="language"
@ -170,6 +171,12 @@
</ng-template>
</div>
<div *ngIf="canUnset" class="unset" title="Unset value">
<button type="button" class="btn btn-sm btn-secondary" [disabled]="isEmpty | async" (click)="unset()">
<i class="icon-close"></i>
</button>
</div>
<sqx-form-hint *ngIf="field.properties.hints?.length > 0">
{{field.properties.hints}}
</sqx-form-hint>

12
frontend/app/features/content/shared/forms/field-editor.component.scss

@ -1,4 +1,8 @@
.field {
& {
position: relative;
}
&-required {
color: $color-theme-error;
}
@ -10,6 +14,14 @@
}
}
.unset {
@include absolute(-.5rem, 0);
i {
font-size: 80%;
}
}
.ui {
& {
margin-bottom: 1rem;

21
frontend/app/features/content/shared/forms/field-editor.component.ts

@ -8,6 +8,8 @@
import { Component, ElementRef, Input, OnChanges, SimpleChanges, ViewChild } from '@angular/core';
import { AbstractControl, FormArray, FormControl } from '@angular/forms';
import { AbstractContentForm, AppLanguageDto, EditContentForm, FieldDto, MathHelper, RootFieldDto, Types } from '@app/shared';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Component({
selector: 'sqx-field-editor',
@ -30,12 +32,17 @@ export class FieldEditorComponent implements OnChanges {
@Input()
public languages: ReadonlyArray<AppLanguageDto>;
@Input()
public canUnset: boolean;
@Input()
public displaySuffix: string;
@ViewChild('editor', { static: false })
public editor: ElementRef;
public isEmpty: Observable<boolean>;
public get field() {
return this.formModel.field;
}
@ -55,10 +62,14 @@ export class FieldEditorComponent implements OnChanges {
public uniqueId = MathHelper.guid();
public ngOnChanges(changes: SimpleChanges) {
const previousControl = changes['control']?.previousValue;
if (changes['formModel']) {
const previousControl: AbstractContentForm<FieldDto, AbstractControl> = changes['formModel'].previousValue;
if (previousControl && Types.isFunction(previousControl['_clearChangeFns'])) {
previousControl['_clearChangeFns']();
if (previousControl && Types.isFunction(previousControl.form['_clearChangeFns'])) {
previousControl.form['_clearChangeFns']();
}
this.isEmpty = this.formModel.form.valueChanges.pipe(map(x => Types.isUndefined(x) || Types.isNull(x)));
}
}
@ -75,4 +86,8 @@ export class FieldEditorComponent implements OnChanges {
}
}
}
public unset() {
this.formModel.form.setValue(undefined);
}
}

26
frontend/app/framework/angular/forms/string-form-control.spec.ts

@ -1,26 +0,0 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { StringFormControl } from './string-form-control';
describe('StringFormControl', () => {
it('should convert empty string to undefined', () => {
const formControl = new StringFormControl();
formControl.setValue('');
expect(formControl.value).toBeUndefined();
});
it('should convert empty string to undefined when patching', () => {
const formControl = new StringFormControl();
formControl.patchValue('');
expect(formControl.value).toBeUndefined();
});
});

39
frontend/app/framework/angular/forms/string-form-control.ts

@ -1,39 +0,0 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
// tslint:disable: readonly-array
import { AbstractControlOptions, AsyncValidatorFn, FormControl, ValidatorFn } from '@angular/forms';
export type ValueOptions = {
onlySelf?: boolean;
emitEvent?: boolean;
emitModelToViewChange?: boolean;
emitViewToModelChange?: boolean;
};
export class StringFormControl extends FormControl {
constructor(formState?: any, validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null, asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null) {
super(formState, validatorOrOpts, asyncValidator);
}
public setValue(value: any, options?: ValueOptions) {
if (value === '') {
value = undefined;
}
super.setValue(value, options);
}
public patchValue(value: any, options?: ValueOptions) {
if (value === '') {
value = undefined;
}
super.patchValue(value, options);
}
}

7
frontend/app/framework/angular/modals/tooltip.directive.ts

@ -47,6 +47,13 @@ export class TooltipDirective {
}
}
@HostListener('click')
public onClick() {
if (this.titleText) {
this.dialogs.tooltip(new Tooltip(this.element.nativeElement, null, this.titlePosition));
}
}
private unsetAttribute() {
try {
this.renderer.setProperty(this.element.nativeElement, 'title', '');

1
frontend/app/framework/declarations.ts

@ -31,7 +31,6 @@ export * from './angular/forms/form-hint.component';
export * from './angular/forms/forms-helper';
export * from './angular/forms/indeterminate-value.directive';
export * from './angular/forms/progress-bar.component';
export * from './angular/forms/string-form-control';
export * from './angular/forms/transform-input.directive';
export * from './angular/forms/validators';
export * from './angular/highlight.pipe';

14
frontend/app/shared/state/contents.forms.ts

@ -7,8 +7,8 @@
// tslint:disable: readonly-array
import { AbstractControl, FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Form, StringFormControl, Types, valueAll$ } from '@app/framework';
import { AbstractControl, FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { Form, Types, valueAll$ } from '@app/framework';
import { BehaviorSubject } from 'rxjs';
import { AppLanguageDto } from './../services/app-languages.service';
import { LanguageDto } from './../services/languages.service';
@ -48,7 +48,7 @@ export class PatchContentForm extends Form<FormGroup, any> {
for (const field of this.editableFields) {
const validators = FieldsValidators.create(field, this.language.isOptional);
this.form.setControl(field.name, new StringFormControl(undefined, { updateOn: FieldUpdateOn.get(field), validators }));
this.form.setControl(field.name, new FormControl(undefined, { updateOn: FieldUpdateOn.get(field), validators }));
}
}
@ -328,7 +328,7 @@ export class FieldForm extends AbstractContentForm<RootFieldDto, FormGroup> {
}
}
export class FieldValueForm extends AbstractContentForm<RootFieldDto, StringFormControl> {
export class FieldValueForm extends AbstractContentForm<RootFieldDto, FormControl> {
constructor(field: RootFieldDto, isOptional: boolean
) {
super(field, FieldValueForm.buildControl(field, isOptional), isOptional);
@ -339,7 +339,7 @@ export class FieldValueForm extends AbstractContentForm<RootFieldDto, StringForm
const validators = FieldsValidators.create(field, isOptional);
return new StringFormControl(value, { updateOn: FieldUpdateOn.get(field), validators });
return new FormControl(value, { updateOn: FieldUpdateOn.get(field), validators });
}
}
@ -467,7 +467,7 @@ export class FieldArrayItemForm extends AbstractContentForm<RootFieldDto, FormGr
}
}
export class FieldArrayItemValueForm extends AbstractContentForm<NestedFieldDto, StringFormControl> {
export class FieldArrayItemValueForm extends AbstractContentForm<NestedFieldDto, FormControl> {
private isRequired = false;
constructor(field: NestedFieldDto, parent: RootFieldDto, rules: CompiledRule[], isOptional: boolean, source?: FieldArrayItemForm
@ -517,7 +517,7 @@ export class FieldArrayItemValueForm extends AbstractContentForm<NestedFieldDto,
const validators = FieldsValidators.create(field, isOptional);
return new StringFormControl(value, { updateOn: FieldUpdateOn.get(field), validators });
return new FormControl(value, { updateOn: FieldUpdateOn.get(field), validators });
}
}

Loading…
Cancel
Save