@gravitee/ui-particles-angular 5.14.0 → 5.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2020/lib/gio-form-focus-first-invalid/gio-form-focus-first-invalid.directive.mjs +6 -6
- package/esm2020/lib/gio-form-json-schema/gio-form-json-schema.component.mjs +32 -17
- package/esm2020/lib/gio-form-json-schema/gio-form-json-schema.module.mjs +21 -6
- package/esm2020/lib/gio-form-json-schema/gio-formly-json-schema.service.mjs +18 -1
- package/esm2020/lib/gio-form-json-schema/type-component/multischema-type.component.mjs +2 -2
- package/esm2020/lib/gio-form-json-schema/wrappers/gio-password-eye.component.mjs +72 -0
- package/fesm2015/gravitee-ui-particles-angular.mjs +136 -28
- package/fesm2015/gravitee-ui-particles-angular.mjs.map +1 -1
- package/fesm2020/gravitee-ui-particles-angular.mjs +142 -28
- package/fesm2020/gravitee-ui-particles-angular.mjs.map +1 -1
- package/lib/gio-form-json-schema/gio-form-json-schema.component.d.ts +2 -0
- package/lib/gio-form-json-schema/gio-form-json-schema.module.d.ts +12 -11
- package/lib/gio-form-json-schema/gio-formly-json-schema.service.d.ts +1 -0
- package/lib/gio-form-json-schema/wrappers/gio-password-eye.component.d.ts +12 -0
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { trigger, transition, style, animate } from '@angular/animations';
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
3
|
import { EventEmitter, Component, HostBinding, Input, Output, HostListener, NgModule, Optional, Self, ViewChild, Directive, Inject, forwardRef, ChangeDetectionStrategy, Injectable, ViewEncapsulation, ContentChildren, Host, ContentChild, InjectionToken } from '@angular/core';
|
|
4
|
-
import { timer, Subject, fromEvent, of, BehaviorSubject, ReplaySubject } from 'rxjs';
|
|
4
|
+
import { timer, Subject, fromEvent, of, BehaviorSubject, combineLatest, ReplaySubject } from 'rxjs';
|
|
5
5
|
import * as i1 from '@angular/material/card';
|
|
6
6
|
import { MatCardModule } from '@angular/material/card';
|
|
7
7
|
import * as i2 from '@angular/material/button';
|
|
@@ -13,7 +13,7 @@ import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
|
|
13
13
|
import * as i3$1 from '@angular/material/form-field';
|
|
14
14
|
import { MatFormFieldControl, MatFormFieldModule, MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field';
|
|
15
15
|
import { isEmpty, toLower, dropRight, isNil, isArray, remove, isObject, cloneDeep, set, uniqueId } from 'lodash';
|
|
16
|
-
import { startWith, map, distinctUntilChanged, tap, debounce, takeUntil, delay, filter, switchMap } from 'rxjs/operators';
|
|
16
|
+
import { startWith, map, distinctUntilChanged, tap, debounce, takeUntil, delay, filter, switchMap, debounceTime } from 'rxjs/operators';
|
|
17
17
|
import * as i7 from '@angular/forms';
|
|
18
18
|
import { FormsModule, FormArray, FormGroup, FormControl, NG_VALUE_ACCESSOR, ReactiveFormsModule, NgControl } from '@angular/forms';
|
|
19
19
|
import * as i2$2 from '@angular/cdk/a11y';
|
|
@@ -2797,6 +2797,7 @@ class GioFormlyJsonSchemaService {
|
|
|
2797
2797
|
return this.formlyJsonschema.toFieldConfig(jsonSchema, {
|
|
2798
2798
|
map: (mappedField, mapSource) => {
|
|
2799
2799
|
mappedField = this.uiTypeMap(mappedField, mapSource);
|
|
2800
|
+
mappedField = this.formatMap(mappedField, mapSource);
|
|
2800
2801
|
mappedField = this.bannerMap(mappedField, mapSource);
|
|
2801
2802
|
mappedField = this.toggleMap(mappedField, mapSource);
|
|
2802
2803
|
return mappedField;
|
|
@@ -2807,6 +2808,22 @@ class GioFormlyJsonSchemaService {
|
|
|
2807
2808
|
mappedField.type = mapSource.gioConfig?.uiType ?? mappedField.type;
|
|
2808
2809
|
return mappedField;
|
|
2809
2810
|
}
|
|
2811
|
+
formatMap(mappedField, mapSource) {
|
|
2812
|
+
if (mapSource.type === 'string' && mapSource.format === 'text') {
|
|
2813
|
+
mappedField.type = 'textarea';
|
|
2814
|
+
mappedField.props = {
|
|
2815
|
+
...mappedField.props,
|
|
2816
|
+
autosize: true,
|
|
2817
|
+
};
|
|
2818
|
+
}
|
|
2819
|
+
else if (mapSource.type === 'string' && mapSource.format === 'password') {
|
|
2820
|
+
mappedField.props = {
|
|
2821
|
+
...mappedField.props,
|
|
2822
|
+
type: 'password',
|
|
2823
|
+
};
|
|
2824
|
+
}
|
|
2825
|
+
return mappedField;
|
|
2826
|
+
}
|
|
2810
2827
|
bannerMap(mappedField, mapSource) {
|
|
2811
2828
|
mappedField.props = {
|
|
2812
2829
|
...mappedField.props,
|
|
@@ -2859,9 +2876,11 @@ class GioFormJsonSchemaComponent {
|
|
|
2859
2876
|
this.options = {};
|
|
2860
2877
|
this.model = {};
|
|
2861
2878
|
this.fields = [];
|
|
2879
|
+
this.loading = true;
|
|
2862
2880
|
this._onChange = () => ({});
|
|
2863
2881
|
this._onTouched = () => ({});
|
|
2864
2882
|
this.touched = false;
|
|
2883
|
+
this.stateChanges$ = new Subject();
|
|
2865
2884
|
if (ngControl) {
|
|
2866
2885
|
// Setting the value accessor directly (instead of using
|
|
2867
2886
|
// the providers `NG_VALUE_ACCESSOR`) to avoid running into a circular import.
|
|
@@ -2881,25 +2900,38 @@ class GioFormJsonSchemaComponent {
|
|
|
2881
2900
|
}
|
|
2882
2901
|
}
|
|
2883
2902
|
ngOnInit() {
|
|
2884
|
-
// When the parent form is touched, mark all the sub formGroup as touched
|
|
2903
|
+
// When the parent form is touched, mark all the sub formGroup as touched ony once
|
|
2885
2904
|
const parentControl = this.ngControl?.control?.parent;
|
|
2886
2905
|
parentControl?.statusChanges
|
|
2887
|
-
?.pipe(takeUntil(this.unsubscribe$), map(() => parentControl?.touched), filter(touched => touched === true),
|
|
2888
|
-
.subscribe()
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
this.ngControl?.control?.setErrors(null);
|
|
2892
|
-
}
|
|
2893
|
-
if (status === 'INVALID') {
|
|
2894
|
-
this.ngControl?.control?.setErrors({ invalid: true });
|
|
2895
|
-
}
|
|
2906
|
+
?.pipe(takeUntil(this.unsubscribe$), map(() => parentControl?.touched), filter(touched => touched === true), distinctUntilChanged())
|
|
2907
|
+
.subscribe(() => {
|
|
2908
|
+
this.formGroup.markAllAsTouched();
|
|
2909
|
+
this.stateChanges$.next();
|
|
2896
2910
|
});
|
|
2897
2911
|
// To simulate the behavior of classic form controls, emit value only when the form is touched
|
|
2898
2912
|
// Allow to keep the formControl pristine until the user interact with it
|
|
2899
|
-
this.formGroup.valueChanges
|
|
2900
|
-
.pipe(takeUntil(this.unsubscribe$),
|
|
2901
|
-
|
|
2902
|
-
|
|
2913
|
+
combineLatest([this.formGroup.statusChanges, this.formGroup.valueChanges])
|
|
2914
|
+
.pipe(takeUntil(this.unsubscribe$),
|
|
2915
|
+
// Group all valueChanges events emit by formly in a single one
|
|
2916
|
+
debounceTime(100))
|
|
2917
|
+
.subscribe(() => {
|
|
2918
|
+
this.stateChanges$.next();
|
|
2919
|
+
});
|
|
2920
|
+
this.stateChanges$.pipe(takeUntil(this.unsubscribe$)).subscribe(() => {
|
|
2921
|
+
const { status, value, touched } = this.formGroup;
|
|
2922
|
+
if (touched) {
|
|
2923
|
+
this._onTouched();
|
|
2924
|
+
this.touched = true;
|
|
2925
|
+
}
|
|
2926
|
+
if (this.touched) {
|
|
2927
|
+
this._onChange(value);
|
|
2928
|
+
if (status === 'VALID') {
|
|
2929
|
+
this.ngControl?.control?.setErrors(null);
|
|
2930
|
+
}
|
|
2931
|
+
if (status === 'INVALID') {
|
|
2932
|
+
this.ngControl?.control?.setErrors({ invalid: true });
|
|
2933
|
+
}
|
|
2934
|
+
}
|
|
2903
2935
|
});
|
|
2904
2936
|
}
|
|
2905
2937
|
ngOnDestroy() {
|
|
@@ -3351,7 +3383,7 @@ GioFjsMultiSchemaTypeComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
|
3351
3383
|
</div>
|
|
3352
3384
|
<formly-field *ngFor="let f of field.fieldGroup" [field]="f"></formly-field>
|
|
3353
3385
|
</div>
|
|
3354
|
-
`, isInline: true, styles: [".
|
|
3386
|
+
`, isInline: true, styles: [".wrapper__title{font-size:16px;font-weight:500;line-height:24px;font:600 14px/20px Golos UI,Roboto,Helvetica Neue,sans-serif;letter-spacing:.4px;margin-bottom:4px}.wrapper:empty{display:none}.wrapper__error{font:400 12px/16px Golos UI,Roboto,Helvetica Neue,sans-serif;letter-spacing:normal;color:#ec4899}\n"], components: [{ type: i1$4.ɵFormlyValidationMessage, selector: "formly-validation-message", inputs: ["field"] }, { type: i1$4.FormlyField, selector: "formly-field", inputs: ["field"] }], directives: [{ type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }] });
|
|
3355
3387
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: GioFjsMultiSchemaTypeComponent, decorators: [{
|
|
3356
3388
|
type: Component,
|
|
3357
3389
|
args: [{ selector: 'gio-fjs-multi-schema-type', template: `
|
|
@@ -3363,7 +3395,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImpo
|
|
|
3363
3395
|
</div>
|
|
3364
3396
|
<formly-field *ngFor="let f of field.fieldGroup" [field]="f"></formly-field>
|
|
3365
3397
|
</div>
|
|
3366
|
-
`, styles: [".
|
|
3398
|
+
`, styles: [".wrapper__title{font-size:16px;font-weight:500;line-height:24px;font:600 14px/20px Golos UI,Roboto,Helvetica Neue,sans-serif;letter-spacing:.4px;margin-bottom:4px}.wrapper:empty{display:none}.wrapper__error{font:400 12px/16px Golos UI,Roboto,Helvetica Neue,sans-serif;letter-spacing:normal;color:#ec4899}\n"] }]
|
|
3367
3399
|
}] });
|
|
3368
3400
|
|
|
3369
3401
|
/*
|
|
@@ -3501,6 +3533,74 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImpo
|
|
|
3501
3533
|
`, styles: [".wrapper{display:flex;flex-direction:column;padding:8px;border:1px solid #d3d5dc;border-radius:8px}.wrapper__header{display:flex}.wrapper__header__text{flex:1 1 auto}.wrapper__header__text__title{font:600 16px/24px Golos UI,Roboto,Helvetica Neue,sans-serif;letter-spacing:.4px;margin-bottom:8px}.wrapper__header__collapse{flex:0 0 auto}.wrapper__header__collapse .collapse-open{transform:rotate(180deg);transition:transform 225ms cubic-bezier(.4,0,.2,1)}.wrapper__header__collapse .collapse-close{transform:rotate(0);transition:transform 225ms cubic-bezier(.4,0,.2,1)}.wrapper__error{font:400 12px/16px Golos UI,Roboto,Helvetica Neue,sans-serif;letter-spacing:normal;color:#ec4899}\n"] }]
|
|
3502
3534
|
}] });
|
|
3503
3535
|
|
|
3536
|
+
/*
|
|
3537
|
+
* Copyright (C) 2023 The Gravitee team (http://gravitee.io)
|
|
3538
|
+
*
|
|
3539
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
3540
|
+
* you may not use this file except in compliance with the License.
|
|
3541
|
+
* You may obtain a copy of the License at
|
|
3542
|
+
*
|
|
3543
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
3544
|
+
*
|
|
3545
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
3546
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
3547
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
3548
|
+
* See the License for the specific language governing permissions and
|
|
3549
|
+
* limitations under the License.
|
|
3550
|
+
*/
|
|
3551
|
+
class GioPasswordEyeWrapperComponent extends FieldWrapper {
|
|
3552
|
+
constructor() {
|
|
3553
|
+
super(...arguments);
|
|
3554
|
+
this.hide = true;
|
|
3555
|
+
}
|
|
3556
|
+
ngAfterViewInit() {
|
|
3557
|
+
if (this.matSuffix) {
|
|
3558
|
+
this.props.suffix = this.matSuffix;
|
|
3559
|
+
}
|
|
3560
|
+
}
|
|
3561
|
+
addonEyeClick($event) {
|
|
3562
|
+
$event.stopPropagation();
|
|
3563
|
+
this.hide = !this.hide;
|
|
3564
|
+
this.props.type = this.hide ? 'password' : 'text';
|
|
3565
|
+
}
|
|
3566
|
+
}
|
|
3567
|
+
GioPasswordEyeWrapperComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: GioPasswordEyeWrapperComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
3568
|
+
GioPasswordEyeWrapperComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.12", type: GioPasswordEyeWrapperComponent, selector: "gio-password-eye-wrapper", viewQueries: [{ propertyName: "matSuffix", first: true, predicate: ["matSuffix"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: `
|
|
3569
|
+
<ng-container #fieldComponent></ng-container>
|
|
3570
|
+
|
|
3571
|
+
<ng-template #matSuffix>
|
|
3572
|
+
<span style="cursor: pointer" (click)="addonEyeClick($event)">
|
|
3573
|
+
<mat-icon [svgIcon]="hide ? 'gio:eye-empty' : 'gio:eye-off'"></mat-icon>
|
|
3574
|
+
</span>
|
|
3575
|
+
</ng-template>
|
|
3576
|
+
`, isInline: true, components: [{ type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }] });
|
|
3577
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: GioPasswordEyeWrapperComponent, decorators: [{
|
|
3578
|
+
type: Component,
|
|
3579
|
+
args: [{
|
|
3580
|
+
selector: 'gio-password-eye-wrapper',
|
|
3581
|
+
template: `
|
|
3582
|
+
<ng-container #fieldComponent></ng-container>
|
|
3583
|
+
|
|
3584
|
+
<ng-template #matSuffix>
|
|
3585
|
+
<span style="cursor: pointer" (click)="addonEyeClick($event)">
|
|
3586
|
+
<mat-icon [svgIcon]="hide ? 'gio:eye-empty' : 'gio:eye-off'"></mat-icon>
|
|
3587
|
+
</span>
|
|
3588
|
+
</ng-template>
|
|
3589
|
+
`,
|
|
3590
|
+
}]
|
|
3591
|
+
}], propDecorators: { matSuffix: [{
|
|
3592
|
+
type: ViewChild,
|
|
3593
|
+
args: ['matSuffix', { static: true }]
|
|
3594
|
+
}] } });
|
|
3595
|
+
function passwordEyeExtension(field) {
|
|
3596
|
+
if (!field.props || (field.wrappers && field.wrappers.indexOf('gio-password-eye') !== -1)) {
|
|
3597
|
+
return;
|
|
3598
|
+
}
|
|
3599
|
+
if (field.props.type === 'password') {
|
|
3600
|
+
field.wrappers = [...(field.wrappers || []), 'gio-password-eye'];
|
|
3601
|
+
}
|
|
3602
|
+
}
|
|
3603
|
+
|
|
3504
3604
|
/*
|
|
3505
3605
|
* Copyright (C) 2015 The Gravitee team (http://gravitee.io)
|
|
3506
3606
|
*
|
|
@@ -3526,7 +3626,8 @@ GioFormJsonSchemaModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0",
|
|
|
3526
3626
|
GioFjsArrayTypeComponent,
|
|
3527
3627
|
GioFjsToggleTypeComponent,
|
|
3528
3628
|
GioFjsHeadersTypeComponent,
|
|
3529
|
-
GioFormFieldWrapperComponent
|
|
3629
|
+
GioFormFieldWrapperComponent,
|
|
3630
|
+
GioPasswordEyeWrapperComponent], imports: [CommonModule,
|
|
3530
3631
|
A11yModule,
|
|
3531
3632
|
ReactiveFormsModule, i1$4.FormlyModule, FormlyMaterialModule,
|
|
3532
3633
|
GioIconsModule,
|
|
@@ -3554,7 +3655,10 @@ GioFormJsonSchemaModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0",
|
|
|
3554
3655
|
{ name: 'uniqueItems', message: 'Should NOT have duplicate items' },
|
|
3555
3656
|
{ name: 'const', message: constValidationMessage },
|
|
3556
3657
|
],
|
|
3557
|
-
wrappers: [
|
|
3658
|
+
wrappers: [
|
|
3659
|
+
{ name: 'gio-with-banner', component: GioFormFieldWrapperComponent },
|
|
3660
|
+
{ name: 'gio-password-eye', component: GioPasswordEyeWrapperComponent },
|
|
3661
|
+
],
|
|
3558
3662
|
types: [
|
|
3559
3663
|
{ name: 'null', component: GioFjsNullTypeComponent, wrappers: ['form-field'] },
|
|
3560
3664
|
{ name: 'array', component: GioFjsArrayTypeComponent },
|
|
@@ -3569,7 +3673,10 @@ GioFormJsonSchemaModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0",
|
|
|
3569
3673
|
component: GioFjsHeadersTypeComponent,
|
|
3570
3674
|
},
|
|
3571
3675
|
],
|
|
3572
|
-
extensions: [
|
|
3676
|
+
extensions: [
|
|
3677
|
+
{ name: 'banner', extension: { onPopulate: bannerExtension } },
|
|
3678
|
+
{ name: 'password-eye', extension: { onPopulate: passwordEyeExtension } },
|
|
3679
|
+
],
|
|
3573
3680
|
extras: {
|
|
3574
3681
|
checkExpressionOn: 'changeDetectionCheck',
|
|
3575
3682
|
},
|
|
@@ -3593,6 +3700,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImpo
|
|
|
3593
3700
|
GioFjsToggleTypeComponent,
|
|
3594
3701
|
GioFjsHeadersTypeComponent,
|
|
3595
3702
|
GioFormFieldWrapperComponent,
|
|
3703
|
+
GioPasswordEyeWrapperComponent,
|
|
3596
3704
|
],
|
|
3597
3705
|
imports: [
|
|
3598
3706
|
CommonModule,
|
|
@@ -3614,7 +3722,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImpo
|
|
|
3614
3722
|
{ name: 'uniqueItems', message: 'Should NOT have duplicate items' },
|
|
3615
3723
|
{ name: 'const', message: constValidationMessage },
|
|
3616
3724
|
],
|
|
3617
|
-
wrappers: [
|
|
3725
|
+
wrappers: [
|
|
3726
|
+
{ name: 'gio-with-banner', component: GioFormFieldWrapperComponent },
|
|
3727
|
+
{ name: 'gio-password-eye', component: GioPasswordEyeWrapperComponent },
|
|
3728
|
+
],
|
|
3618
3729
|
types: [
|
|
3619
3730
|
{ name: 'null', component: GioFjsNullTypeComponent, wrappers: ['form-field'] },
|
|
3620
3731
|
{ name: 'array', component: GioFjsArrayTypeComponent },
|
|
@@ -3629,7 +3740,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImpo
|
|
|
3629
3740
|
component: GioFjsHeadersTypeComponent,
|
|
3630
3741
|
},
|
|
3631
3742
|
],
|
|
3632
|
-
extensions: [
|
|
3743
|
+
extensions: [
|
|
3744
|
+
{ name: 'banner', extension: { onPopulate: bannerExtension } },
|
|
3745
|
+
{ name: 'password-eye', extension: { onPopulate: passwordEyeExtension } },
|
|
3746
|
+
],
|
|
3633
3747
|
extras: {
|
|
3634
3748
|
checkExpressionOn: 'changeDetectionCheck',
|
|
3635
3749
|
},
|
|
@@ -3685,17 +3799,17 @@ class GioFormFocusInvalidDirective {
|
|
|
3685
3799
|
onFormSubmit() {
|
|
3686
3800
|
const selector = '.ng-invalid[formControlName],input.ng-invalid,mat-select.ng-invalid,textarea.ng-invalid,.gio-ng-invalid';
|
|
3687
3801
|
try {
|
|
3802
|
+
// Mark all controls as touched to display errors
|
|
3803
|
+
if (this.formGroupDirective) {
|
|
3804
|
+
this.formGroupDirective.control.markAllAsTouched();
|
|
3805
|
+
this.formGroupDirective.control.updateValueAndValidity();
|
|
3806
|
+
}
|
|
3688
3807
|
let invalidControl = this.renderer.selectRootElement(selector, true);
|
|
3689
3808
|
// If the form is a GioFormJsonSchema, we need to focus the first invalid control inside
|
|
3690
3809
|
if (invalidControl.tagName === 'GIO-FORM-JSON-SCHEMA') {
|
|
3691
3810
|
invalidControl = invalidControl.querySelector(selector);
|
|
3692
3811
|
}
|
|
3693
3812
|
if (invalidControl) {
|
|
3694
|
-
// Mark all controls as touched to display errors
|
|
3695
|
-
if (this.formGroupDirective) {
|
|
3696
|
-
this.formGroupDirective.control.markAllAsTouched();
|
|
3697
|
-
this.formGroupDirective.control.updateValueAndValidity();
|
|
3698
|
-
}
|
|
3699
3813
|
invalidControl.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
3700
3814
|
invalidControl.focus({ preventScroll: true });
|
|
3701
3815
|
}
|