Skip to content

Commit

Permalink
feat(forms): support for dynamic form-control change
Browse files Browse the repository at this point in the history
  • Loading branch information
dtsanevmw committed Nov 23, 2023
1 parent 350110e commit b66ae92
Show file tree
Hide file tree
Showing 7 changed files with 195 additions and 2 deletions.
5 changes: 4 additions & 1 deletion projects/angular/clarity.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { DoCheck } from '@angular/core';
import { ElementRef } from '@angular/core';
import { EmbeddedViewRef } from '@angular/core';
import { EventEmitter } from '@angular/core';
import { FormControl } from '@angular/forms';
import { FormGroup } from '@angular/forms';
import { FormGroupDirective } from '@angular/forms';
import { FormGroupName } from '@angular/forms';
Expand Down Expand Up @@ -4833,6 +4834,8 @@ export class WrappedFormControl<W extends DynamicWrapper> implements OnInit, OnD
// (undocumented)
protected el: ElementRef<any>;
// (undocumented)
set formControl(control: FormControl);
// (undocumented)
protected getProviderFromContainer<T>(token: Type<T> | InjectionToken<T>, notFoundValue?: T): T;
// (undocumented)
get id(): string;
Expand All @@ -4858,7 +4861,7 @@ export class WrappedFormControl<W extends DynamicWrapper> implements OnInit, OnD
// (undocumented)
protected wrapperType: Type<W>;
// (undocumented)
static ɵdir: i0.ɵɵDirectiveDeclaration<WrappedFormControl<any>, never, never, { "id": "id"; }, {}, never, never, false, never>;
static ɵdir: i0.ɵɵDirectiveDeclaration<WrappedFormControl<any>, never, never, { "id": "id"; "formControl": "formControl"; }, {}, never, never, false, never>;
// (undocumented)
static ɵfac: i0.ɵɵFactoryDeclaration<WrappedFormControl<any>, never>;
}
Expand Down
9 changes: 8 additions & 1 deletion projects/angular/src/forms/common/wrapped-control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
Type,
ViewContainerRef,
} from '@angular/core';
import { NgControl } from '@angular/forms';
import { FormControl, NgControl } from '@angular/forms';
import { Subscription } from 'rxjs';

import { DynamicWrapper } from '../../utils/host-wrapping/dynamic-wrapper';
Expand Down Expand Up @@ -100,6 +100,13 @@ export class WrappedFormControl<W extends DynamicWrapper> implements OnInit, OnD
}
}

@Input('formControl')
set formControl(control: FormControl) {
if (this.ngControlService && control) {
this.ngControlService.setControl(this.ngControl);
}
}

ngOnInit() {
this._containerInjector = new HostWrapper(this.wrapperType, this.vcr, this.index);
this.controlIdService = this._containerInjector.get(ControlIdService);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<h1>Reproduce Step</h1>
<ol>
<li>Select ECS, Public signed radio is automatically selected. Click Signature (empty textarea).</li>
<li style="color: red">
When switching platform dropdown to Cloudian, signature textarea has value, but its successful state is not updated.
clr-success not show
</li>
</ol>

<form clrForm [formGroup]="form">
<clr-select-container>
<label>{{ 'CHOOSE_PLATFORM' }}</label>
<select class="w-60" clrSelect formControlName="platform">
<option value="CLOUDIAN">CLOUDIAN</option>
<option value="ECS">ECS</option>
</select>
<clr-control-error> {{ 'REQUIRED' }} </clr-control-error>
</clr-select-container>

<clr-input-container>
<label>{{ 'S3_URL' }}</label>
<input clrInput type="text" [formControl]="$any(form)?.get('s3')?.get('url')" />
<clr-control-error>{{ 'INVALID_HTTPS_DESC' }}</clr-control-error>
</clr-input-container>

<clr-radio-container clrInline>
<label>{{ 'CERTIFICATE_VALIDATION' }}</label>
<clr-radio-wrapper>
<input type="radio" clrRadio [name]="'s3-cert-validate'" value="tlsSignature" [formControl]="certValidation" />
<label>{{ 'SIGNATURE' }}</label>
</clr-radio-wrapper>
<clr-radio-wrapper>
<input type="radio" clrRadio [name]="'s3-cert-validate'" value="publicSigned" [formControl]="certValidation" />
<label>{{ 'PUBLIC_SIGNED' }}</label>
</clr-radio-wrapper>
<clr-control-error> {{ 'REQUIRED' }} </clr-control-error>
</clr-radio-container>

<clr-textarea-container *ngIf="certValidation.value === 'tlsSignature'">
<label>{{ 'SIGNATURE' }}</label>
<textarea clrTextarea [formControl]="$any(form).get('s3').get('tlsSignature')"></textarea>
<clr-control-helper>{{ 'SIGNATURE_DESC' }}</clr-control-helper>
<clr-control-success>I should show when successful!!!</clr-control-success>
<clr-control-error> {{ 'REQUIRED' }} </clr-control-error>
</clr-textarea-container>
</form>
131 changes: 131 additions & 0 deletions projects/demo/src/app/forms/dynamic-controls/dynamic-controls.demo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*
* Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved.
* This software is released under MIT license.
* The full license information can be found in LICENSE in the root directory of this project.
*/

import { Component, inject } from '@angular/core';
import { FormControl, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';

@Component({
selector: 'dynamic-controls-demo',
templateUrl: './dynamic-controls.demo.html',
})
export class DynamicControlsDemo {
// radio control
readonly certValidation = new FormControl<string | null>(null, Validators.required);

fb = inject(UntypedFormBuilder);

form: UntypedFormGroup = this.fb.group({
platform: new FormControl<string | null>(null, [Validators.required]),
});

ngOnInit() {
this.registerPlatformChange();

this.registerCertValidateChange();
}

private registerPlatformChange() {
this.form.controls.platform.valueChanges.subscribe(value => {
this.form.removeControl('s3');
this.form.removeControl('iam');
this.form.removeControl('console');

switch (value) {
case 'CLOUDIAN':
this.addControlsForCloudian();
break;
case 'ECS':
this.addControlsForECS();
break;
default:
break;
}

this.setCertValidationValue();
});
}

private addControlsForCloudian() {
this.addS3Control('cloudian signature');
this.addIAMControl();
}

private addControlsForECS() {
this.addS3Control();
this.addConsoleControl();
}

private addS3Control(signature?: string) {
this.form.addControl(
's3',
this.fb.group({
url: this.fb.control('', [Validators.required]),
tlsSignature: this.fb.control(
{
value: signature,
disabled: true,
},
Validators.required
),
})
);
}

private addIAMControl() {
this.form.addControl(
'iam',
this.fb.group({
url: this.fb.control('', [Validators.required]),
tlsSignature: this.fb.control(
{
value: '',
disabled: true,
},
Validators.required
),
})
);
}

private addConsoleControl() {
this.form.addControl(
'console',
this.fb.group({
url: ['', [Validators.required]],
secretKey: ['', [Validators.required]],
})
);
}

// set radio based on form value
private setCertValidationValue() {
const signatureControl = this.form.controls['s3'].get('tlsSignature') as FormControl;

const value = signatureControl.value ? 'tlsSignature' : 'publicSigned';

this.certValidation.setValue(value);
}

private registerCertValidateChange() {
this.certValidation.valueChanges.subscribe(value => {
const tlsSignature = this.form.controls['s3'].get('tlsSignature') as FormControl;

if (value === 'tlsSignature') {
tlsSignature.enable({ emitEvent: false });
} else {
// public signed
tlsSignature.disable({ emitEvent: false });
}

setTimeout(() => {
if (tlsSignature.value) {
tlsSignature.markAsTouched();
tlsSignature.updateValueAndValidity();
}
});
});
}
}
3 changes: 3 additions & 0 deletions projects/demo/src/app/forms/forms.demo.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { FormsRadioDemo } from './controls/radio';
import { FormsSelectDemo } from './controls/select';
import { FormsTextDemo } from './controls/text';
import { FormsTextareaDemo } from './controls/textarea';
import { DynamicControlsDemo } from './dynamic-controls/dynamic-controls.demo';
import { FormsDemo } from './forms.demo';
import { ROUTING } from './forms.demo.routing';
import { FormsGenericContainerDemo } from './generic-container/generic-container';
Expand Down Expand Up @@ -69,6 +70,7 @@ import { FormsValidationDemo } from './validation/validation';
FormsA11yDemo,
FormsGenericContainerDemo,
FormsValidationDemo,
DynamicControlsDemo,
],
exports: [
FormsDemo,
Expand Down Expand Up @@ -97,6 +99,7 @@ import { FormsValidationDemo } from './validation/validation';
FormsA11yDemo,
FormsGenericContainerDemo,
FormsValidationDemo,
DynamicControlsDemo,
],
})
export class FormsDemoModule {}
2 changes: 2 additions & 0 deletions projects/demo/src/app/forms/forms.demo.routing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { FormsRadioDemo } from './controls/radio';
import { FormsSelectDemo } from './controls/select';
import { FormsTextDemo } from './controls/text';
import { FormsTextareaDemo } from './controls/textarea';
import { DynamicControlsDemo } from './dynamic-controls/dynamic-controls.demo';
import { FormsDemo } from './forms.demo';
import { FormsGenericContainerDemo } from './generic-container/generic-container';
import { FormsInputGroupDemo } from './input-group/input-group';
Expand Down Expand Up @@ -67,6 +68,7 @@ const ROUTES: Routes = [
{ path: 'a11y', component: FormsA11yDemo },
{ path: 'generic-container', component: FormsGenericContainerDemo },
{ path: 'validation', component: FormsValidationDemo },
{ path: 'dynamic-controls', component: DynamicControlsDemo },
],
},
];
Expand Down
1 change: 1 addition & 0 deletions projects/demo/src/app/forms/forms.demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import { Component } from '@angular/core';
<li><a [routerLink]="['./a11y']">a11y</a></li>
<li><a [routerLink]="['./generic-container']">Generic Container</a></li>
<li><a [routerLink]="['./validation']">Validation</a></li>
<li><a [routerLink]="['./dynamic-controls']">Dynamic Controls Reproduction</a></li>
</ul>
<router-outlet></router-outlet>
`,
Expand Down

0 comments on commit b66ae92

Please sign in to comment.