From 4af38a04a247cb205b0103b949627da9c448d111 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Thu, 12 Jan 2017 00:38:39 +0100 Subject: [PATCH] Form validation improved --- .../pages/content/content-page.component.ts | 29 ++++- .../schemas/pages/schema/field.component.html | 16 +-- .../schema/schema-edit-form.component.html | 16 +-- .../schema/schema-edit-form.component.ts | 6 +- .../pages/schema/schema-page.component.html | 16 +-- .../pages/schema/schema-page.component.ts | 9 +- .../schema/types/boolean-ui.component.html | 8 +- .../schema/types/boolean-ui.component.ts | 7 +- .../schema/types/number-ui.component.html | 8 +- .../pages/schema/types/number-ui.component.ts | 11 +- .../schema/types/string-ui.component.html | 8 +- .../pages/schema/types/string-ui.component.ts | 7 +- .../pages/schemas/schema-form.component.html | 24 +--- .../pages/schemas/schema-form.component.ts | 5 +- .../pages/clients/client.component.html | 8 +- .../pages/clients/clients-page.component.html | 15 +-- .../pages/clients/clients-page.component.ts | 9 +- .../angular/control-errors.component.html | 7 ++ .../angular/control-errors.component.scss | 2 + .../angular/control-errors.component.ts | 118 ++++++++++++++++++ .../app/framework/angular/validators.spec.ts | 4 +- .../app/framework/angular/validators.ts | 63 ++++++++-- src/Squidex/app/framework/declarations.ts | 1 + src/Squidex/app/framework/module.ts | 3 + .../shared/components/app-form.component.html | 25 +--- .../shared/components/app-form.component.ts | 9 +- 26 files changed, 264 insertions(+), 170 deletions(-) create mode 100644 src/Squidex/app/framework/angular/control-errors.component.html create mode 100644 src/Squidex/app/framework/angular/control-errors.component.scss create mode 100644 src/Squidex/app/framework/angular/control-errors.component.ts diff --git a/src/Squidex/app/features/content/pages/content/content-page.component.ts b/src/Squidex/app/features/content/pages/content/content-page.component.ts index 006e8ac08..8facb3de4 100644 --- a/src/Squidex/app/features/content/pages/content/content-page.component.ts +++ b/src/Squidex/app/features/content/pages/content/content-page.component.ts @@ -6,15 +6,18 @@ */ import { Component } from '@angular/core'; -import { AbstractControl, FormControl, FormGroup } from '@angular/forms'; +import { AbstractControl, FormControl, FormGroup, ValidatorFn, Validators } from '@angular/forms'; import { ActivatedRoute } from '@angular/router'; import { AppComponentBase, AppsStoreService, NotificationService, + NumberFieldPropertiesDto, SchemaDetailsDto, - UsersProviderService + StringFieldPropertiesDto, + UsersProviderService, + ValidatorsEx } from 'shared'; @Component({ @@ -51,9 +54,27 @@ export class ContentPageComponent extends AppComponentBase { const controls: { [key: string]: AbstractControl } = {}; for (const field of schema.fields) { - const formControl = new FormControl(); + const validators: ValidatorFn[] = []; - controls[field.name] = formControl; + if (field.properties.isRequired) { + validators.push(Validators.required); + } + if (field.properties instanceof NumberFieldPropertiesDto) { + validators.push(ValidatorsEx.between(field.properties.minValue, field.properties.maxValue)); + } + if (field.properties instanceof StringFieldPropertiesDto) { + if (field.properties.minLength) { + validators.push(Validators.minLength(field.properties.minLength)); + } + if (field.properties.maxLength) { + validators.push(Validators.maxLength(field.properties.maxLength)); + } + if (field.properties.pattern) { + validators.push(ValidatorsEx.pattern(field.properties.pattern, field.properties.patternMessage)); + } + } + + controls[field.name] = new FormControl(validators); } this.contentForm = new FormGroup(controls); diff --git a/src/Squidex/app/features/schemas/pages/schema/field.component.html b/src/Squidex/app/features/schemas/pages/schema/field.component.html index 199288676..07ffe5fe6 100644 --- a/src/Squidex/app/features/schemas/pages/schema/field.component.html +++ b/src/Squidex/app/features/schemas/pages/schema/field.component.html @@ -86,13 +86,7 @@
-
-
- - Label can not have more than 100 characters. - -
-
+ @@ -106,13 +100,7 @@
-
-
- - Hints can not have more than 100 characters. - -
-
+ diff --git a/src/Squidex/app/features/schemas/pages/schema/schema-edit-form.component.html b/src/Squidex/app/features/schemas/pages/schema/schema-edit-form.component.html index 550373dc9..5602b1f7f 100644 --- a/src/Squidex/app/features/schemas/pages/schema/schema-edit-form.component.html +++ b/src/Squidex/app/features/schemas/pages/schema/schema-edit-form.component.html @@ -8,13 +8,7 @@
-
-
- - Label can not have more than 100 characters. - -
-
+
@@ -22,13 +16,7 @@
-
-
- - Hints can not have more than 1000 characters. - -
-
+
diff --git a/src/Squidex/app/features/schemas/pages/schema/schema-edit-form.component.ts b/src/Squidex/app/features/schemas/pages/schema/schema-edit-form.component.ts index 134b1eeb4..e159cd0cc 100644 --- a/src/Squidex/app/features/schemas/pages/schema/schema-edit-form.component.ts +++ b/src/Squidex/app/features/schemas/pages/schema/schema-edit-form.component.ts @@ -9,7 +9,6 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { - fadeAnimation, Notification, NotificationService, SchemasService @@ -20,10 +19,7 @@ import { SchemaPropertiesDto } from './schema-properties'; @Component({ selector: 'sqx-schema-edit-form', styleUrls: ['./schema-edit-form.component.scss'], - templateUrl: './schema-edit-form.component.html', - animations: [ - fadeAnimation - ] + templateUrl: './schema-edit-form.component.html' }) export class SchemaEditFormComponent implements OnInit { @Output() diff --git a/src/Squidex/app/features/schemas/pages/schema/schema-page.component.html b/src/Squidex/app/features/schemas/pages/schema/schema-page.component.html index c75b13583..24dfac6f3 100644 --- a/src/Squidex/app/features/schemas/pages/schema/schema-page.component.html +++ b/src/Squidex/app/features/schemas/pages/schema/schema-page.component.html @@ -43,25 +43,15 @@
+
-
-
- - Name is required. - - - Name can not have more than 40 characters. - - - Name can contain lower case letters (a-z), numbers and dashes (not at the end). - -
-
+
+
diff --git a/src/Squidex/app/features/schemas/pages/schema/schema-page.component.ts b/src/Squidex/app/features/schemas/pages/schema/schema-page.component.ts index b358dcbb3..7d691444b 100644 --- a/src/Squidex/app/features/schemas/pages/schema/schema-page.component.ts +++ b/src/Squidex/app/features/schemas/pages/schema/schema-page.component.ts @@ -24,7 +24,8 @@ import { SchemaDetailsDto, SchemasService, UpdateFieldDto, - UsersProviderService + UsersProviderService, + ValidatorsEx } from 'shared'; import { SchemaPropertiesDto } from './schema-properties'; @@ -63,7 +64,7 @@ export class SchemaPageComponent extends AppComponentBase implements OnInit { [ Validators.required, Validators.maxLength(40), - Validators.pattern('[a-z0-9]+(\-[a-z0-9]+)*') + ValidatorsEx.pattern('[a-z0-9]+(\-[a-z0-9]+)*', 'Name can contain lower case letters (a-z), numbers and dashes (not at the end).') ]] }); @@ -203,6 +204,10 @@ export class SchemaPageComponent extends AppComponentBase implements OnInit { } } + public resetFieldForm() { + this.addFieldForm.reset(); + } + public onSchemaSaved(properties: SchemaPropertiesDto) { this.updateProperties(properties); diff --git a/src/Squidex/app/features/schemas/pages/schema/types/boolean-ui.component.html b/src/Squidex/app/features/schemas/pages/schema/types/boolean-ui.component.html index 497dc8037..68bb2a0f0 100644 --- a/src/Squidex/app/features/schemas/pages/schema/types/boolean-ui.component.html +++ b/src/Squidex/app/features/schemas/pages/schema/types/boolean-ui.component.html @@ -3,13 +3,7 @@
-
-
- - Placeholder can not have more than 100 characters. - -
-
+ diff --git a/src/Squidex/app/features/schemas/pages/schema/types/boolean-ui.component.ts b/src/Squidex/app/features/schemas/pages/schema/types/boolean-ui.component.ts index f2b310b7d..69e2d432e 100644 --- a/src/Squidex/app/features/schemas/pages/schema/types/boolean-ui.component.ts +++ b/src/Squidex/app/features/schemas/pages/schema/types/boolean-ui.component.ts @@ -8,15 +8,12 @@ import { Component, Input, OnInit } from '@angular/core'; import { FormControl, FormGroup, Validators } from '@angular/forms'; -import { fadeAnimation, BooleanFieldPropertiesDto } from 'shared'; +import { BooleanFieldPropertiesDto } from 'shared'; @Component({ selector: 'sqx-boolean-ui', styleUrls: ['boolean-ui.component.scss'], - templateUrl: 'boolean-ui.component.html', - animations: [ - fadeAnimation - ] + templateUrl: 'boolean-ui.component.html' }) export class BooleanUIComponent implements OnInit { @Input() diff --git a/src/Squidex/app/features/schemas/pages/schema/types/number-ui.component.html b/src/Squidex/app/features/schemas/pages/schema/types/number-ui.component.html index f88c9472d..40ae04c0f 100644 --- a/src/Squidex/app/features/schemas/pages/schema/types/number-ui.component.html +++ b/src/Squidex/app/features/schemas/pages/schema/types/number-ui.component.html @@ -3,13 +3,7 @@
-
-
- - Placeholder can not have more than 100 characters. - -
-
+ diff --git a/src/Squidex/app/features/schemas/pages/schema/types/number-ui.component.ts b/src/Squidex/app/features/schemas/pages/schema/types/number-ui.component.ts index ad69e6065..339c096a5 100644 --- a/src/Squidex/app/features/schemas/pages/schema/types/number-ui.component.ts +++ b/src/Squidex/app/features/schemas/pages/schema/types/number-ui.component.ts @@ -9,19 +9,12 @@ import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { FormControl, FormGroup, Validators } from '@angular/forms'; import { Observable, Subscription } from 'rxjs'; -import { - fadeAnimation, - FloatConverter, - NumberFieldPropertiesDto -} from 'shared'; +import { FloatConverter, NumberFieldPropertiesDto } from 'shared'; @Component({ selector: 'sqx-number-ui', styleUrls: ['number-ui.component.scss'], - templateUrl: 'number-ui.component.html', - animations: [ - fadeAnimation - ] + templateUrl: 'number-ui.component.html' }) export class NumberUIComponent implements OnDestroy, OnInit { private editorSubscription: Subscription; diff --git a/src/Squidex/app/features/schemas/pages/schema/types/string-ui.component.html b/src/Squidex/app/features/schemas/pages/schema/types/string-ui.component.html index d35e3fa3b..dfd8c0e6e 100644 --- a/src/Squidex/app/features/schemas/pages/schema/types/string-ui.component.html +++ b/src/Squidex/app/features/schemas/pages/schema/types/string-ui.component.html @@ -3,13 +3,7 @@
-
-
- - Placeholder can not have more than 100 characters. - -
-
+ diff --git a/src/Squidex/app/features/schemas/pages/schema/types/string-ui.component.ts b/src/Squidex/app/features/schemas/pages/schema/types/string-ui.component.ts index 1acee345f..61fd06114 100644 --- a/src/Squidex/app/features/schemas/pages/schema/types/string-ui.component.ts +++ b/src/Squidex/app/features/schemas/pages/schema/types/string-ui.component.ts @@ -9,15 +9,12 @@ import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { FormControl, FormGroup, Validators } from '@angular/forms'; import { Observable, Subscription } from 'rxjs'; -import { fadeAnimation, StringFieldPropertiesDto } from 'shared'; +import { StringFieldPropertiesDto } from 'shared'; @Component({ selector: 'sqx-string-ui', styleUrls: ['string-ui.component.scss'], - templateUrl: 'string-ui.component.html', - animations: [ - fadeAnimation - ] + templateUrl: 'string-ui.component.html' }) export class StringUIComponent implements OnDestroy, OnInit { private editorSubscription: Subscription; diff --git a/src/Squidex/app/features/schemas/pages/schemas/schema-form.component.html b/src/Squidex/app/features/schemas/pages/schemas/schema-form.component.html index f461fbb30..37b9050e7 100644 --- a/src/Squidex/app/features/schemas/pages/schemas/schema-form.component.html +++ b/src/Squidex/app/features/schemas/pages/schemas/schema-form.component.html @@ -8,29 +8,15 @@
-
-
- - Name is required. - - - Name can not have more than 40 characters. - - - Name can contain lower case letters (a-z), numbers and dashes only (not at the end). - -
-
+ -

- The schema name becomes part of the api url,
e.g https://{{appName}}.squidex.io/{{schemaName | async}}/. -

-

- It must contain lower case letters (a-z), numbers and dashes only, and cannot be longer than 40 characters. The name cannot be changed later. -

+ The schema name becomes part of the api url,
e.g https://{{appName}}.squidex.io/{{schemaName | async}}/. +
+ + It must contain lower case letters (a-z), numbers and dashes only, and cannot be longer than 40 characters. The name cannot be changed later.
diff --git a/src/Squidex/app/features/schemas/pages/schemas/schema-form.component.ts b/src/Squidex/app/features/schemas/pages/schemas/schema-form.component.ts index 8765e1c20..b37411fe4 100644 --- a/src/Squidex/app/features/schemas/pages/schemas/schema-form.component.ts +++ b/src/Squidex/app/features/schemas/pages/schemas/schema-form.component.ts @@ -15,7 +15,8 @@ import { DateTime, fadeAnimation, SchemaDto, - SchemasService + SchemasService, + ValidatorsEx } from 'shared'; const FALLBACK_NAME = 'my-schema'; @@ -45,7 +46,7 @@ export class SchemaFormComponent { [ Validators.required, Validators.maxLength(40), - Validators.pattern('[a-z0-9]+(\-[a-z0-9]+)*') + ValidatorsEx.pattern('[a-z0-9]+(\-[a-z0-9]+)*', 'Name can contain lower case letters (a-z), numbers and dashes only (not at the end).') ]] }); diff --git a/src/Squidex/app/features/settings/pages/clients/client.component.html b/src/Squidex/app/features/settings/pages/clients/client.component.html index d7f39d1b3..e364e32d2 100644 --- a/src/Squidex/app/features/settings/pages/clients/client.component.html +++ b/src/Squidex/app/features/settings/pages/clients/client.component.html @@ -15,13 +15,7 @@
-
-
- - Name is required. - -
-
+
diff --git a/src/Squidex/app/features/settings/pages/clients/clients-page.component.html b/src/Squidex/app/features/settings/pages/clients/clients-page.component.html index 284482b7a..126585a20 100644 --- a/src/Squidex/app/features/settings/pages/clients/clients-page.component.html +++ b/src/Squidex/app/features/settings/pages/clients/clients-page.component.html @@ -22,24 +22,13 @@
diff --git a/src/Squidex/app/features/settings/pages/clients/clients-page.component.ts b/src/Squidex/app/features/settings/pages/clients/clients-page.component.ts index d05620c56..3f4430260 100644 --- a/src/Squidex/app/features/settings/pages/clients/clients-page.component.ts +++ b/src/Squidex/app/features/settings/pages/clients/clients-page.component.ts @@ -19,7 +19,8 @@ import { MessageBus, NotificationService, UpdateAppClientDto, - UsersProviderService + UsersProviderService, + ValidatorsEx } from 'shared'; function rename(client: AppClientDto, name: string): AppClientDto { @@ -40,7 +41,7 @@ export class ClientsPageComponent extends AppComponentBase implements OnInit { [ Validators.required, Validators.maxLength(40), - Validators.pattern('[a-z0-9]+(\-[a-z0-9]+)*') + ValidatorsEx.pattern('[a-z0-9]+(\-[a-z0-9]+)*', 'Name can contain lower case letters (a-z), numbers and dashes (not at the end).') ]] }); @@ -88,6 +89,10 @@ export class ClientsPageComponent extends AppComponentBase implements OnInit { }); } + public resetClientForm() { + this.addClientForm.reset(); + } + public attachClient() { this.addClientForm.markAsDirty(); diff --git a/src/Squidex/app/framework/angular/control-errors.component.html b/src/Squidex/app/framework/angular/control-errors.component.html new file mode 100644 index 000000000..351a7e126 --- /dev/null +++ b/src/Squidex/app/framework/angular/control-errors.component.html @@ -0,0 +1,7 @@ +
+
+ + {{message}} + +
+
\ No newline at end of file diff --git a/src/Squidex/app/framework/angular/control-errors.component.scss b/src/Squidex/app/framework/angular/control-errors.component.scss new file mode 100644 index 000000000..d1951ab29 --- /dev/null +++ b/src/Squidex/app/framework/angular/control-errors.component.scss @@ -0,0 +1,2 @@ +@import '_mixins'; +@import '_vars'; \ No newline at end of file diff --git a/src/Squidex/app/framework/angular/control-errors.component.ts b/src/Squidex/app/framework/angular/control-errors.component.ts new file mode 100644 index 000000000..d2c7a9d68 --- /dev/null +++ b/src/Squidex/app/framework/angular/control-errors.component.ts @@ -0,0 +1,118 @@ +/* + * Squidex Headless CMS + * + * @license + * Copyright (c) Sebastian Stehle. All rights reserved + */ + +import { ChangeDetectorRef, ChangeDetectionStrategy, Component, Host, Input, OnChanges, OnInit, OnDestroy, Optional } from '@angular/core'; +import { AbstractControl, FormGroupDirective } from '@angular/forms'; +import { Subscription } from 'rxjs'; + +import { fadeAnimation } from './animations'; + +const DEFAULT_ERRORS: { [key: string]: string } = { + required: '{field} is required.', + pattern: '{field} does not follow the pattern.', + patternMessage: '{message}', + minValue: '{field} must be larget than {minValue}.', + maxValue: '{field} must be larget than {maxValue}.', + minLength: '{field} must have more than {minLength} characters.', + maxLength: '{field} cannot have more than {maxLength} characters.', + validNumber: '{field} is not a valid number.', + validValues: '{field} is not a valid value.' +}; + +@Component({ + selector: 'sqx-control-errors', + styleUrls: ['./control-errors.component.scss'], + templateUrl: './control-errors.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + animations: [ + fadeAnimation + ] +}) +export class ControlErrorsComponent implements OnChanges, OnInit, OnDestroy { + private formSubscription: Subscription; + private displayFieldName: string; + private control: AbstractControl; + + @Input() + public for: string; + + @Input() + public fieldName: string; + + @Input() + public errors: string; + + @Input() + public submitted: boolean; + + public errorMessages: string[]; + + constructor(@Optional() @Host() private readonly form: FormGroupDirective, + private readonly changeDetector: ChangeDetectorRef + ) { + if (!this.form) { + throw new Error('control-errors must be used with a parent formGroup directive'); + } + } + + public ngOnChanges() { + if (this.fieldName) { + this.displayFieldName = this.fieldName; + } else if (this.for) { + this.displayFieldName = this.for.substr(0, 1).toUpperCase() + this.for.substr(1); + } + + this.update(); + } + + public ngOnDestroy() { + this.formSubscription.unsubscribe(); + } + + public ngOnInit() { + this.control = this.form.form.controls[this.for]; + + this.formSubscription = + this.form.form.statusChanges.merge(this.control.statusChanges) + .subscribe(_ => { + this.update(); + }); + } + + private update() { + if (!this.control) { + return; + } + + if (this.control.invalid && (this.control.touched || this.form.form.touched)) { + const errors: string[] = []; + + for (let key in this.control.errors) { + if (this.control.errors.hasOwnProperty(key)) { + let message: string = (this.errors ? this.errors[key] : null) || DEFAULT_ERRORS[key]; + let properties = this.control.errors[key]; + + for (let property in properties) { + if (properties.hasOwnProperty(property)) { + message = message.replace('{' + property + '}', properties[property]); + } + } + + message = message.replace('{field}', this.displayFieldName); + + errors.push(message); + } + } + + this.errorMessages = errors.length > 0 ? errors : null; + } else { + this.errorMessages = null; + } + + this.changeDetector.markForCheck(); + } +} \ No newline at end of file diff --git a/src/Squidex/app/framework/angular/validators.spec.ts b/src/Squidex/app/framework/angular/validators.spec.ts index 7a0bced37..342710ac1 100644 --- a/src/Squidex/app/framework/angular/validators.spec.ts +++ b/src/Squidex/app/framework/angular/validators.spec.ts @@ -7,13 +7,13 @@ import { FormControl } from '@angular/forms'; -import { Validators } from './../'; +import { ValidatorsEx } from './../'; describe('Validators', () => { let validateBetween: any; beforeEach(() => { - validateBetween = Validators.between(10, 200); + validateBetween = ValidatorsEx.between(10, 200); }); it('should return error when not a number', () => { diff --git a/src/Squidex/app/framework/angular/validators.ts b/src/Squidex/app/framework/angular/validators.ts index c4d8d6a4f..fc0fa095f 100644 --- a/src/Squidex/app/framework/angular/validators.ts +++ b/src/Squidex/app/framework/angular/validators.ts @@ -5,19 +5,66 @@ * Copyright (c) Sebastian Stehle. All rights reserved */ -import { AbstractControl } from '@angular/forms'; +import { AbstractControl, ValidatorFn, Validators } from '@angular/forms'; -export class Validators { - public static between(minValue: number, maxValue: number) { +export class ValidatorsEx { + public static pattern(pattern: string | RegExp, message: string | undefined = undefined): ValidatorFn { + if (!pattern) { + return Validators.nullValidator; + } + + let regex: RegExp; + let regexStr: string; + + if (typeof pattern === 'string') { + regexStr = `^${pattern}$`; + regex = new RegExp(regexStr); + } else { + regexStr = pattern.toString(); + regex = pattern; + } + + return (control: AbstractControl): { [key: string]: any } => { + const n: string = control.value; + + if (n == null || n.length === 0) { + return null; + } + + if (!regex.test(n)) { + if (message) { + return { patternMessage: { requiredPattern: regexStr, actualValue: n, message } }; + } else { + return { pattern: { requiredPattern: regexStr, actualValue: n } }; + } + } + + return null; + }; + } + + public static between(minValue: number | undefined, maxValue: number | undefined) { return (control: AbstractControl): { [key: string]: any } => { const n: number = control.value; if (typeof n !== 'number') { - return { 'validNumber': false }; - } else if (n < minValue) { - return { 'minValue': { 'requiredValue': minValue, 'actualValue': n } }; - } else if (n > maxValue) { - return { 'maxValue': { 'requiredValue': maxValue, 'actualValue': n } }; + return { validNumber: false }; + } else if (minValue && n < minValue) { + return { minValue: { minValue, actualValue: n } }; + } else if (maxValue && n > maxValue) { + return { maxValue: { maxValue, actualValue: n } }; + } + + return {}; + }; + } + + public static validValues(values: T[]) { + return (control: AbstractControl): { [key: string]: any } => { + const n: T = control.value; + + if (values.indexOf(n) < 0) { + return { validValues: false }; } return {}; diff --git a/src/Squidex/app/framework/declarations.ts b/src/Squidex/app/framework/declarations.ts index 8168d1601..0a443319d 100644 --- a/src/Squidex/app/framework/declarations.ts +++ b/src/Squidex/app/framework/declarations.ts @@ -9,6 +9,7 @@ export * from './angular/animations'; export * from './angular/autocomplete.component'; export * from './angular/validators'; export * from './angular/cloak.directive'; +export * from './angular/control-errors.component'; export * from './angular/copy.directive'; export * from './angular/date-time.pipes'; export * from './angular/focus-on-change.directive'; diff --git a/src/Squidex/app/framework/module.ts b/src/Squidex/app/framework/module.ts index 277aa31e3..fa8a5a97f 100644 --- a/src/Squidex/app/framework/module.ts +++ b/src/Squidex/app/framework/module.ts @@ -15,6 +15,7 @@ import { AutocompleteComponent, ClipboardService, CloakDirective, + ControlErrorsComponent, CopyDirective, DayOfWeekPipe, DayPipe, @@ -55,6 +56,7 @@ import { declarations: [ AutocompleteComponent, CloakDirective, + ControlErrorsComponent, CopyDirective, DayOfWeekPipe, DayPipe, @@ -80,6 +82,7 @@ import { exports: [ AutocompleteComponent, CloakDirective, + ControlErrorsComponent, CopyDirective, DayOfWeekPipe, DayPipe, diff --git a/src/Squidex/app/shared/components/app-form.component.html b/src/Squidex/app/shared/components/app-form.component.html index 4484d2088..9cd1a7a5f 100644 --- a/src/Squidex/app/shared/components/app-form.component.html +++ b/src/Squidex/app/shared/components/app-form.component.html @@ -8,29 +8,16 @@
-
-
- - Name is required. - - - Name can not have more than 40 characters. - - - Name can contain lower case letters (a-z), numbers and dashes only (not at the end). - -
-
+ -

- The app name becomes part of the api url,
e.g https://{{appName | async}}.squidex.io/. -

-

- It must contain lower case letters (a-z), numbers and dashes only, and cannot be longer than 40 characters. The name cannot be changed later. -

+ The app name becomes part of the api url,
e.g https://{{appName | async}}.squidex.io/. +
+ + + It must contain lower case letters (a-z), numbers and dashes only, and cannot be longer than 40 characters. The name cannot be changed later.
diff --git a/src/Squidex/app/shared/components/app-form.component.ts b/src/Squidex/app/shared/components/app-form.component.ts index 7f5b2aec3..b1157483b 100644 --- a/src/Squidex/app/shared/components/app-form.component.ts +++ b/src/Squidex/app/shared/components/app-form.component.ts @@ -9,7 +9,7 @@ import { Component, EventEmitter, Output } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { Observable } from 'rxjs'; -import { fadeAnimation } from 'framework'; +import { ValidatorsEx } from 'framework'; import { AppsStoreService } from './../services/apps-store.service'; import { AppDto, CreateAppDto } from './../services/apps.service'; @@ -19,10 +19,7 @@ const FALLBACK_NAME = 'my-app'; @Component({ selector: 'sqx-app-form', styleUrls: ['./app-form.component.scss'], - templateUrl: './app-form.component.html', - animations: [ - fadeAnimation - ] + templateUrl: './app-form.component.html' }) export class AppFormComponent { @Output() @@ -38,7 +35,7 @@ export class AppFormComponent { [ Validators.required, Validators.maxLength(40), - Validators.pattern('[a-z0-9]+(\-[a-z0-9]+)*') + ValidatorsEx.pattern('[a-z0-9]+(\-[a-z0-9]+)*', 'Name can contain lower case letters (a-z), numbers and dashes (not at the end).') ]] });