Skip to content

Commit

Permalink
fix: (platform) form refactoring (#3083)
Browse files Browse the repository at this point in the history
* refactor platform form

* move things to separate files

* fix tests, add nested form-groups

* proper inject flag to retrieve ngForm

* fix typing in checkbox-group template

* add comment

* minor

* rid of contentChildern

* drop extra variable

* minor

* add step input module to platform module
  • Loading branch information
dimamarksman committed Aug 28, 2020
1 parent baa6510 commit 8d53c3d
Show file tree
Hide file tree
Showing 30 changed files with 708 additions and 383 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Component, AfterViewChecked } from '@angular/core';
import { Component, AfterViewInit } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { map } from 'rxjs/operators';

@Component({
selector: 'fdp-tristate-checkbox',
templateUrl: 'platform-tristate-checkbox.component.html'
})
export class PlatformChekboxTristateComponent implements AfterViewChecked {
export class PlatformChekboxTristateComponent implements AfterViewInit {
public havana = false;
public beirut: boolean = null;
public budapest = 'Yes';
Expand All @@ -26,7 +26,7 @@ export class PlatformChekboxTristateComponent implements AfterViewChecked {
public choices: Object = { termsAndConditions: true, marketing: true, newsletter: false };

// code for nested form group with tristate checkbox.
ngAfterViewChecked(): void {
ngAfterViewInit(): void {
this.setAgreementsOnAcceptAllChange();
this.setControlOnAgreementsChange();
}
Expand All @@ -42,8 +42,9 @@ export class PlatformChekboxTristateComponent implements AfterViewChecked {
}

private setControlOnAgreementsChange(): void {
this.registrationForm.controls.agreements.valueChanges
.pipe(
this.registrationForm
.get('agreements')
.valueChanges.pipe(
map((agreements) => this.getValuesFromObject(agreements)),
map((agreementsValues: boolean[]) => {
const agreeAll = agreementsValues.reduce((overall, value) => value && overall, true);
Expand All @@ -62,19 +63,25 @@ export class PlatformChekboxTristateComponent implements AfterViewChecked {

private acceptAll(accept: boolean): void {
if (accept !== null) {
this.registrationForm.controls.agreements.patchValue({
marketing: accept,
newsletter: accept,
termsAndConditions: accept
});
this.registrationForm.get('agreements').patchValue(
{
marketing: accept,
newsletter: accept,
termsAndConditions: accept
},
{ emitEvent: false }
);
}
}

private setAcceptAll(value: boolean): void {
if (this.registrationForm.controls.acceptAll.value !== value) {
this.registrationForm.patchValue({
acceptAll: value
});
if (this.registrationForm.get('acceptAll')?.value !== value) {
this.registrationForm.patchValue(
{
acceptAll: value
},
{ emitEvent: false }
);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
Checkbox Group created From List of Objects.
</fd-docs-section-title>
<description>
Checkbox Group Created From List of Objects. Here it is possible to create some checkboxes as disabled
and others enabled.
Checkbox Group Created From List of Objects. Here it is possible to create some checkboxes as disabled and others
enabled.
</description>
<component-example>
<fdp-platform-checkbox-group-list-object></fdp-platform-checkbox-group-list-object>
Expand All @@ -24,7 +24,9 @@
<fd-docs-section-title [id]="'projectionExample'" [componentName]="'PlatformCheckboxGroupContentCheckboxComponent'">
Checkbox Group created From content projected Checkboxes.
</fd-docs-section-title>
<description>Checkbox Group Created from projected Checkboxes. This helps in localisation of checkbox labels.</description>
<description
>Checkbox Group Created from projected Checkboxes. This helps in localisation of checkbox labels.</description
>
<component-example>
<fdp-platform-checkbox-group-content></fdp-platform-checkbox-group-content>
</component-example>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
<fdp-form-group [multiLayout]="true" [formGroup]="customForm">
<fdp-form-field id="switch-config" label="Switch with Config" zone="zLeft" rank="4">
<fdp-switch
name="switch-config"
formControlName="switch"
></fdp-switch>
<fdp-form-group [multiLayout]="true" [object]="model" #fg>
<fdp-form-field #ff id="switch" label="Switch with Config" zone="zLeft" rank="4">
<fdp-switch name="switch" [formControl]="ff.formControl"></fdp-switch>
</fdp-form-field>
</fdp-form-group>

<div style="padding-left: 2rem;">form value: {{ customForm.getRawValue() | json }}</div>
<div style="padding-left: 2rem;">form value: {{ fg.formGroup.getRawValue() | json }}</div>
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Component } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { SwitchConfig } from '@fundamental-ngx/platform';

export const switchConfigFactory = SwitchConfig.createProviderFactory({
Expand All @@ -17,7 +16,7 @@ export const customSwitchConfigProvider = {
providers: [customSwitchConfigProvider]
})
export class SwitchConfigExampleComponent {
customForm = new FormGroup({
switch: new FormControl(false)
});
model: { switch: boolean } = {
switch: true
};
}
52 changes: 39 additions & 13 deletions libs/platform/src/lib/components/form/base.input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,21 @@ import {
OnChanges,
OnDestroy,
OnInit,
ViewChild,
Optional,
Self,
SimpleChanges,
ViewChild
SkipSelf,
Host
} from '@angular/core';
import { FormFieldControl, Status } from './form-control';
import { BaseComponent } from '../base';
import { ControlValueAccessor, FormControl, NgControl, NgForm } from '@angular/forms';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { Subject } from 'rxjs';

import { BaseComponent } from '../base';

import { FormFieldControl, Status } from './form-control';
import { FormField } from './form-field';

let randomId = 0;

/**
Expand Down Expand Up @@ -57,8 +61,8 @@ export abstract class BaseInput extends BaseComponent
}

/**
* readOnly Value to Mark component read only
*/
* readOnly Value to Mark component read only
*/
@Input()
readonly: boolean;

Expand Down Expand Up @@ -123,31 +127,49 @@ export abstract class BaseInput extends BaseComponent
*/
readonly stateChanges: Subject<any> = new Subject<any>();

readonly formField: FormField | null = null;

// @formatter:off
onChange = (_: any) => {};
onTouched = () => {};

// @formatter:on

constructor(
protected _cd: ChangeDetectorRef,
@Optional() @Self() public ngControl: NgControl,
@Optional() @Self() public ngForm: NgForm
cd: ChangeDetectorRef,
@Optional() @Self() readonly ngControl: NgControl,
@Optional() @SkipSelf() readonly ngForm: NgForm,
@Optional() @SkipSelf() @Host() formField: FormField,
@Optional() @SkipSelf() @Host() formControl: FormFieldControl<any>
) {
super(_cd);
/**
* We do not use Injector.get() approach here because there is a bug
* with this signature https://github.com/angular/angular/issues/31776
* where "get()" method doesn't take into account "flag" option"
*
*/
super(cd);

if (this.ngControl) {
this.ngControl.valueAccessor = this;
}

// We have to ignore "formField" if there is "formControl" wrapper
this.formField = formField && !formControl ? formField : null;
}

ngOnChanges(): void {
this.stateChanges.next('input: ngOnChanges');
}

ngOnInit(): void {
if (!this.id || !this.name) {
throw new Error('form input must have [id] and [name] attribute.');
}
}

ngOnChanges(changes: SimpleChanges): void {
this.stateChanges.next('input: ngOnChanges');
if (this.formField) {
this.formField.registerFormFieldControl(this);
}
}

/**
Expand Down Expand Up @@ -176,6 +198,9 @@ export abstract class BaseInput extends BaseComponent
this.stateChanges.complete();
this._destroyed.next();
this._destroyed.complete();
if (this.formField) {
this.formField.unregisterFormFieldControl(this);
}
}

setDisabledState(isDisabled: boolean): void {
Expand Down Expand Up @@ -249,6 +274,7 @@ export abstract class BaseInput extends BaseComponent
if (newState !== oldState) {
this._status = newState ? 'error' : undefined;
this.stateChanges.next('updateErrorState');
this._cd.markForCheck();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
checkboxValue: getLookupValue(item),
contentDensity: contentDensity,
labeltext: getDisplayValue(item),
disabled: item.disabled ? item.disabled : disabled
disabled: getListItemDisabledValue(item)
}
"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,26 @@ import {
Component,
ContentChildren,
ChangeDetectionStrategy,
ChangeDetectorRef,
EventEmitter,
Input,
Optional,
Output,
QueryList,
Self,
ViewEncapsulation,
ViewChildren
ViewChildren,
forwardRef,
ChangeDetectorRef,
Optional,
Self,
SkipSelf,
Host
} from '@angular/core';
import { NgControl, NgForm } from '@angular/forms';
import { NgForm, NgControl } from '@angular/forms';

import { CollectionBaseInput } from '../collection-base.input';
import { CheckboxComponent } from '../checkbox/checkbox.component';
import { PlatformCheckboxChange } from '../checkbox/checkbox.component';
import { FormFieldControl } from '../form-control';
import { FormField } from '../form-field';

/**
* Checkbox group implementation based on the
Expand All @@ -30,7 +35,7 @@ import { FormFieldControl } from '../form-control';
templateUrl: './checkbox-group.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
providers: [{ provide: FormFieldControl, useExisting: CheckboxGroupComponent, multi: true }]
providers: [{ provide: FormFieldControl, useExisting: forwardRef(() => CheckboxGroupComponent), multi: true }]
})
export class CheckboxGroupComponent extends CollectionBaseInput {
/**
Expand All @@ -44,7 +49,7 @@ export class CheckboxGroupComponent extends CollectionBaseInput {
}

/**
* To Dispaly multiple checkboxes in a line
* To Display multiple checkboxes in a line
*/
@Input()
isInline = false;
Expand All @@ -61,11 +66,13 @@ export class CheckboxGroupComponent extends CollectionBaseInput {
readonly valueChange: EventEmitter<PlatformCheckboxChange> = new EventEmitter<PlatformCheckboxChange>();

constructor(
private _changeDetector: ChangeDetectorRef,
@Optional() @Self() public ngControl: NgControl,
@Optional() @Self() public ngForm: NgForm
cd: ChangeDetectorRef,
@Optional() @Self() ngControl: NgControl,
@Optional() @SkipSelf() ngForm: NgForm,
@Optional() @SkipSelf() @Host() formField: FormField,
@Optional() @SkipSelf() @Host() formControl: FormFieldControl<any>
) {
super(_changeDetector, ngControl, ngForm);
super(cd, ngControl, ngForm, formField, formControl);
}

writeValue(value: any): void {
Expand All @@ -85,16 +92,21 @@ export class CheckboxGroupComponent extends CollectionBaseInput {
}

/**
* acess display value for objects, acts as checkbox label.
* access display value for objects, acts as checkbox label.
*/
public getDisplayValue(item: any): string {
return this.displayValue(item);
}

/**
* acess lookup value for objects, acts as checkbox value.
* access lookup value for objects, acts as checkbox value.
*/
public getLookupValue(item: any): string {
return this.lookupValue(item);
}

/** @hidden */
public getListItemDisabledValue(item: CheckboxGroupComponent['list'][number]): boolean {
return this.disabled || typeof item === 'string' ? this.disabled : item.disabled;
}
}

0 comments on commit 8d53c3d

Please sign in to comment.