Browse Source

Fix/value changes (#487)

* Fix for value changes

* References

# Conflicts:
#	frontend/app/features/content/shared/forms/array-item.component.ts

* More fixes for value changes.
pull/489/head
Sebastian Stehle 6 years ago
committed by GitHub
parent
commit
aa49450b8b
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      frontend/app/features/content/pages/content/content-page.component.ts
  2. 6
      frontend/app/features/content/shared/forms/array-item.component.ts
  3. 4
      frontend/app/features/content/shared/forms/stock-photo-editor.component.html
  4. 34
      frontend/app/features/content/shared/forms/stock-photo-editor.component.ts
  5. 2
      frontend/app/features/schemas/pages/schema/fields/types/assets-validation.component.html
  6. 2
      frontend/app/features/schemas/pages/schema/fields/types/string-validation.component.html
  7. 35
      frontend/app/features/schemas/pages/schema/fields/types/string-validation.component.ts
  8. 4
      frontend/app/framework/angular/forms/editors/autocomplete.component.ts
  9. 2
      frontend/app/framework/angular/forms/editors/dropdown.component.html
  10. 13
      frontend/app/framework/angular/forms/editors/dropdown.component.ts
  11. 6
      frontend/app/framework/angular/forms/editors/tag-editor.component.ts
  12. 46
      frontend/app/framework/angular/forms/forms-helper.spec.ts
  13. 4
      frontend/app/framework/angular/forms/forms-helper.ts
  14. 13
      frontend/app/shared/components/forms/references-dropdown.component.ts
  15. 12
      frontend/app/shared/components/forms/references-tags.component.ts
  16. 5
      frontend/app/shared/state/contents.forms.ts

4
frontend/app/features/content/pages/content/content-page.component.ts

@ -282,6 +282,10 @@ export class ContentPageComponent extends ResourceOwner implements CanComponentD
}
private checkPendingChanges(action: string) {
if (this.content && !this.content.canUpdateAny) {
return of(true);
}
return this.contentForm.hasChanged() ?
this.dialogs.confirm('Unsaved changes', `You have unsaved changes.\n\nWhen you ${action} you will loose them.\n\n**Do you want to continue anyway?**`) :
of(true);

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

@ -8,7 +8,6 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, OnDestroy, Output, QueryList, SimpleChanges, ViewChildren } from '@angular/core';
import { AbstractControl, FormGroup } from '@angular/forms';
import { Observable, Subscription } from 'rxjs';
import { startWith } from 'rxjs/operators';
import {
AppLanguageDto,
@ -16,7 +15,8 @@ import {
FieldDto,
FieldFormatter,
invalid$,
RootFieldDto
RootFieldDto,
value$
} from '@app/shared';
import { FieldEditorComponent } from './field-editor.component';
@ -103,7 +103,7 @@ export class ArrayItemComponent implements OnChanges, OnDestroy {
this.unsubscribeFromForm();
this.subscription =
this.itemForm.valueChanges.pipe(startWith(this.itemForm.value))
value$(this.itemForm)
.subscribe(() => {
this.updateTitle();
});

4
frontend/app/features/content/shared/forms/stock-photo-editor.component.html

@ -10,8 +10,8 @@
<i class="icon-close"></i>
</button>
<div *ngIf="valueThumb | async; let thumbUrl; else noThumb" class="preview">
<img [src]="thumbUrl" />
<div *ngIf="stockPhotoThumbnail | async; let url; else noThumb" class="preview">
<img [src]="url" />
</div>
<ng-template #noThumb>

34
frontend/app/features/content/shared/forms/stock-photo-editor.component.ts

@ -8,14 +8,15 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, OnInit } from '@angular/core';
import { FormControl, NG_VALUE_ACCESSOR } from '@angular/forms';
import { of } from 'rxjs';
import { debounceTime, distinctUntilChanged, map, shareReplay, startWith, switchMap, tap } from 'rxjs/operators';
import { debounceTime, map, switchMap, tap } from 'rxjs/operators';
import {
StatefulControlComponent,
StockPhotoDto,
StockPhotoService,
thumbnail,
Types
Types,
value$
} from '@app/shared';
interface State {
@ -30,6 +31,8 @@ export const SQX_STOCK_PHOTO_EDITOR_CONTROL_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => StockPhotoEditorComponent), multi: true
};
const NO_EMIT = { emitEvent: false };
@Component({
selector: 'sqx-stock-photo-editor',
styleUrls: ['./stock-photo-editor.component.scss'],
@ -42,18 +45,11 @@ export const SQX_STOCK_PHOTO_EDITOR_CONTROL_VALUE_ACCESSOR: any = {
export class StockPhotoEditorComponent extends StatefulControlComponent<State, string> implements OnInit {
public valueControl = new FormControl('');
public valueThumb =
this.valueControl.valueChanges.pipe(
startWith(this.valueControl.value),
shareReplay(1),
map(value => thumbnail(value, 400) || value));
public stockPhotoThumbnail = value$(this.valueControl).pipe(map(v => thumbnail(v, 400) || v));
public stockPhotoSearch = new FormControl('');
public stockPhotos =
this.stockPhotoSearch.valueChanges.pipe(
startWith(this.stockPhotoSearch.value),
distinctUntilChanged(),
value$(this.stockPhotoSearch).pipe(
debounceTime(500),
tap(query => {
if (query && query.length > 0) {
@ -78,8 +74,6 @@ export class StockPhotoEditorComponent extends StatefulControlComponent<State, s
}
public ngOnInit() {
this.own(this.valueThumb);
this.own(
this.valueControl.valueChanges
.subscribe(value => {
@ -89,9 +83,19 @@ export class StockPhotoEditorComponent extends StatefulControlComponent<State, s
public writeValue(obj: string) {
if (Types.isString(obj)) {
this.valueControl.setValue(obj, { emitEvent: true });
this.valueControl.setValue(obj);
} else {
this.valueControl.setValue('');
}
}
public setDisabledState(isDisabled: boolean): void {
super.setDisabledState(isDisabled);
if (isDisabled) {
this.stockPhotoSearch.disable(NO_EMIT);
} else {
this.valueControl.setValue('', { emitEvent: true });
this.stockPhotoSearch.enable(NO_EMIT);
}
}

2
frontend/app/features/schemas/pages/schema/fields/types/assets-validation.component.html

@ -111,7 +111,7 @@
<div class="form-group2 row">
<label class="col-3 col-form-label">
Allowed Extensions
File Extensions
</label>
<div class="col-6">

2
frontend/app/features/schemas/pages/schema/fields/types/string-validation.component.html

@ -61,7 +61,7 @@
{{patternName}}
</small>
</div>
<div class="form-group row" *ngIf="showPatternMessage">
<div class="form-group row" *ngIf="showPatternMessage | async">
<label class="col-3 col-form-label" for="{{field.fieldId}}_fieldPatternMessage">Pattern Message</label>
<div class="col-6">

35
frontend/app/features/schemas/pages/schema/fields/types/string-validation.component.ts

@ -5,7 +5,7 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Component, Input, OnInit } from '@angular/core';
import { Component, Input, OnChanges, OnInit } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { Observable } from 'rxjs';
@ -13,12 +13,14 @@ import {
fadeAnimation,
FieldDto,
hasNoValue$,
hasValue$,
ModalModel,
PatternDto,
ResourceOwner,
RootFieldDto,
StringFieldPropertiesDto,
Types
Types,
value$
} from '@app/shared';
@Component({
@ -29,7 +31,7 @@ import {
fadeAnimation
]
})
export class StringValidationComponent extends ResourceOwner implements OnInit {
export class StringValidationComponent extends ResourceOwner implements OnChanges, OnInit {
@Input()
public editForm: FormGroup;
@ -43,7 +45,7 @@ export class StringValidationComponent extends ResourceOwner implements OnInit {
public patterns: ReadonlyArray<PatternDto>;
public showDefaultValue: Observable<boolean>;
public showPatternMessage: boolean;
public showPatternMessage: Observable<boolean>;
public showPatternSuggestions: Observable<boolean>;
public patternName: string;
@ -80,13 +82,16 @@ export class StringValidationComponent extends ResourceOwner implements OnInit {
this.showPatternSuggestions =
hasNoValue$(this.editForm.controls['pattern']);
this.showPatternSuggestions =
hasNoValue$(this.editForm.controls['pattern']);
this.showPatternMessage =
this.editForm.controls['pattern'].value && this.editForm.controls['pattern'].value.trim().length > 0;
hasValue$(this.editForm.controls['pattern']);
this.own(
this.editForm.controls['pattern'].valueChanges
value$(this.editForm.controls['pattern'])
.subscribe((value: string) => {
if (!value || value.length === 0) {
if (!value) {
this.editForm.controls['patternMessage'].setValue(undefined);
}
@ -96,22 +101,28 @@ export class StringValidationComponent extends ResourceOwner implements OnInit {
this.setPatternName();
}
public ngOnChanges() {
this.setPatternName();
}
public setPattern(pattern: PatternDto) {
this.patternName = pattern.name;
this.editForm.controls['pattern'].setValue(pattern.pattern);
this.editForm.controls['patternMessage'].setValue(pattern.message);
this.showPatternMessage = true;
}
private setPatternName() {
const value = this.editForm.controls['pattern'].value;
if (!value) {
this.patternName = '';
} else {
const matchingPattern = this.patterns.find(x => x.pattern === this.editForm.controls['pattern'].value);
if (matchingPattern) {
this.patternName = matchingPattern.name;
} else if (this.editForm.controls['pattern'].value && this.editForm.controls['pattern'].value.trim() !== '') {
this.patternName = 'Advanced';
} else {
this.patternName = '';
this.patternName = 'Advanced';
}
}
}
}

4
frontend/app/framework/angular/forms/editors/autocomplete.component.ts

@ -20,8 +20,6 @@ export interface AutocompleteSource {
find(query: string): Observable<ReadonlyArray<any>>;
}
const NO_EMIT = { emitEvent: false };
export const SQX_AUTOCOMPLETE_CONTROL_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => AutocompleteComponent), multi: true
};
@ -34,6 +32,8 @@ interface State {
suggestedIndex: number;
}
const NO_EMIT = { emitEvent: false };
@Component({
selector: 'sqx-autocomplete',
styleUrls: ['./autocomplete.component.scss'],

2
frontend/app/framework/angular/forms/editors/dropdown.component.html

@ -17,7 +17,7 @@
<ng-container *sqxModal="dropdown">
<div class="control-dropdown" [sqxAnchoredTo]="input" position="bottom-left">
<div *ngIf="canSearch" class="search-form">
<input class="form-control search" [formControl]="queryInput" [disabled]="snapshot.isDisabled" placeholder="Search" (keydown)="onKeyDown($event)" sqxFocusOnInit />
<input class="form-control search" [formControl]="queryInput" placeholder="Search" (keydown)="onKeyDown($event)" sqxFocusOnInit />
</div>
<div class="control-dropdown-items" #container>

13
frontend/app/framework/angular/forms/editors/dropdown.component.ts

@ -34,6 +34,8 @@ interface State {
query?: RegExp;
}
const NO_EMIT = { emitEvent: false };
@Component({
selector: 'sqx-dropdown',
styleUrls: ['./dropdown.component.scss'],
@ -134,6 +136,16 @@ export class DropdownComponent extends StatefulControlComponent<State, ReadonlyA
this.selectIndex(this.items && obj ? this.items.indexOf(obj) : 0, false);
}
public setDisabledState(isDisabled: boolean): void {
super.setDisabledState(isDisabled);
if (isDisabled) {
this.queryInput.disable(NO_EMIT);
} else {
this.queryInput.enable(NO_EMIT);
}
}
public onKeyDown(event: KeyboardEvent) {
switch (event.keyCode) {
case Keys.UP:
@ -208,6 +220,5 @@ export class DropdownComponent extends StatefulControlComponent<State, ReadonlyA
this.next(s => ({ ...s, selectedIndex, selectedItem: value }));
}
}
}

6
frontend/app/framework/angular/forms/editors/tag-editor.component.ts

@ -139,6 +139,8 @@ interface State {
items: ReadonlyArray<TagValue>;
}
const NO_EMIT = { emitEvent: false };
@Component({
selector: 'sqx-tag-editor',
styleUrls: ['./tag-editor.component.scss'],
@ -302,9 +304,9 @@ export class TagEditorComponent extends StatefulControlComponent<State, Readonly
super.setDisabledState(isDisabled);
if (isDisabled) {
this.addInput.disable();
this.addInput.disable(NO_EMIT);
} else {
this.addInput.enable();
this.addInput.enable(NO_EMIT);
}
}

46
frontend/app/framework/angular/forms/forms-helper.spec.ts

@ -0,0 +1,46 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { FormControl, Validators } from '@angular/forms';
import { value$ } from './forms-helper';
describe('FormHelpers', () => {
describe('value$', () => {
it('should provide change values', () => {
const form = new FormControl('1', Validators.required);
const values: any[] = [];
value$(form).subscribe(x => {
values.push(x);
});
form.setValue('2');
form.setValue('3');
expect(values).toEqual(['1', '2', '3']);
});
it('should not trigger on disable', () => {
const form = new FormControl('1', Validators.required);
const values: any[] = [];
value$(form).subscribe(x => {
values.push(x);
});
form.setValue('2');
form.enable();
form.setValue('3');
form.disable();
expect(values).toEqual(['1', '2', '3']);
});
});
});

4
frontend/app/framework/angular/forms/forms-helper.ts

@ -7,7 +7,7 @@
import { AbstractControl, FormArray, FormGroup } from '@angular/forms';
import { Observable } from 'rxjs';
import { distinctUntilChanged, map, startWith } from 'rxjs/operators';
import { distinctUntilChanged, filter, map, startWith } from 'rxjs/operators';
import { Types } from './../../utils/types';
@ -26,7 +26,7 @@ export function invalid$(form: AbstractControl): Observable<boolean> {
}
export function value$<T = any>(form: AbstractControl): Observable<T> {
return form.valueChanges.pipe(startWith(form.value));
return form.valueChanges.pipe(startWith(form.value), filter(_ => form.enabled), distinctUntilChanged());
}
export function hasValue$(form: AbstractControl): Observable<boolean> {

13
frontend/app/shared/components/forms/references-dropdown.component.ts

@ -16,7 +16,8 @@ import {
LanguageDto,
StatefulControlComponent,
Types,
UIOptions
UIOptions,
value$
} from '@app/shared/internal';
export const SQX_REFERENCES_DROPDOWN_CONTROL_VALUE_ACCESSOR: any = {
@ -83,7 +84,7 @@ export class ReferencesDropdownComponent extends StatefulControlComponent<State,
this.itemCount = uiOptions.get('referencesDropdownItemCount');
this.own(
this.selectionControl.valueChanges
value$(this.selectionControl)
.subscribe((value: ContentName) => {
if (value && value.id) {
this.callTouched();
@ -119,19 +120,19 @@ export class ReferencesDropdownComponent extends StatefulControlComponent<State,
this.selectContent();
}, () => {
this.selectionControl.disable();
this.selectionControl.disable(NO_EMIT);
});
} else {
this.selectionControl.disable();
this.selectionControl.disable(NO_EMIT);
}
}
}
public setDisabledState(isDisabled: boolean) {
if (isDisabled) {
this.selectionControl.disable();
this.selectionControl.disable(NO_EMIT);
} else if (this.isValid) {
this.selectionControl.enable();
this.selectionControl.enable(NO_EMIT);
}
super.setDisabledState(isDisabled);

12
frontend/app/shared/components/forms/references-tags.component.ts

@ -24,8 +24,6 @@ export const SQX_REFERENCES_TAGS_CONTROL_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => ReferencesTagsComponent), multi: true
};
const NO_EMIT = { emitEvent: false };
class TagsConverter implements Converter {
public suggestions: ReadonlyArray<TagValue> = [];
@ -70,6 +68,8 @@ interface State {
converter: TagsConverter;
}
const NO_EMIT = { emitEvent: false };
@Component({
selector: 'sqx-references-tags',
styleUrls: ['./references-tags.component.scss'],
@ -141,9 +141,9 @@ export class ReferencesTagsComponent extends StatefulControlComponent<State, Rea
public setDisabledState(isDisabled: boolean) {
if (isDisabled) {
this.selectionControl.disable();
this.selectionControl.disable(NO_EMIT);
} else if (this.isValid) {
this.selectionControl.enable();
this.selectionControl.enable(NO_EMIT);
}
super.setDisabledState(isDisabled);
@ -159,11 +159,11 @@ export class ReferencesTagsComponent extends StatefulControlComponent<State, Rea
if (this.isValid && this.contentItems && this.contentItems.length > 0) {
converter = new TagsConverter(this.language, this.contentItems);
this.selectionControl.enable();
this.selectionControl.enable(NO_EMIT);
} else {
converter = new TagsConverter(null!, []);
this.selectionControl.disable();
this.selectionControl.disable(NO_EMIT);
}
this.next({ converter });

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

@ -15,7 +15,8 @@ import {
Form,
formControls,
Types,
ValidatorsEx
ValidatorsEx,
value$
} from '@app/framework';
import { AppLanguageDto } from './../services/app-languages.service';
@ -468,7 +469,7 @@ export class EditContentForm extends Form<FormGroup, any> {
) {
super(new FormGroup({}));
this.form.valueChanges.subscribe(value => {
value$(this.form).subscribe(value => {
this.value.next(value);
});

Loading…
Cancel
Save