From 38fcf7d52cdfb962805d8eebfe793db6568ce503 Mon Sep 17 00:00:00 2001 From: MaxKless <34165455+MaxKless@users.noreply.github.com> Date: Tue, 16 Mar 2021 14:58:03 +0100 Subject: [PATCH] refactor: use postWrappers extension instead of injecting config (#620) --- docs/guides/formly.md | 11 +++++---- .../user-budget-form.component.ts | 8 +++---- .../registration-page.component.spec.ts | 9 ++----- .../registration-page.component.ts | 7 +++--- .../us/address-form-us.configuration.ts | 6 ++--- .../extensions/post-wrappers-extension.ts | 24 +++++++++++++++++++ src/app/shared/formly/formly.module.ts | 9 ++++++- 7 files changed, 50 insertions(+), 24 deletions(-) create mode 100644 src/app/shared/formly/extensions/post-wrappers-extension.ts diff --git a/docs/guides/formly.md b/docs/guides/formly.md index 15dd70bb1f..984a52c8db 100644 --- a/docs/guides/formly.md +++ b/docs/guides/formly.md @@ -245,8 +245,9 @@ Refer to the tables below for an overview of these parts. ### Extensions -| Name | Functionality | Relevant templateOptions | -| ------------------------ | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------ | -| critical-default-values | Sets required attributes on `FormlyFieldConfigs` that are missing them. | ---- | -| hide-if-empty | Hides fields of type `ish-select-field` that have an empty `options` attribute. | `options`: Used to determine emptiness. | -| translate-select-options | Automatically translates option labels and adds a placeholder option. | `placeholder`: used to determine whether to set placeholder and its text | +| Name | Functionality | Relevant templateOptions | +| ------------------------ | ------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | +| critical-default-values | Sets required attributes on `FormlyFieldConfigs` that are missing them. | ---- | +| hide-if-empty | Hides fields of type `ish-select-field` that have an empty `options` attribute. | `options`: Used to determine emptiness. | +| translate-select-options | Automatically translates option labels and adds a placeholder option. | `placeholder`: used to determine whether to set placeholder and its text | +| post-wrappers | Appends wrappers to the default ones defined in the `FormlyModule` | `postWrappers`: `string[]` of extensions to append to the default wrappers | diff --git a/projects/organization-management/src/app/components/user-budget-form/user-budget-form.component.ts b/projects/organization-management/src/app/components/user-budget-form/user-budget-form.component.ts index 44edfa8060..7b9b6b8ede 100644 --- a/projects/organization-management/src/app/components/user-budget-form/user-budget-form.component.ts +++ b/projects/organization-management/src/app/components/user-budget-form/user-budget-form.component.ts @@ -1,7 +1,7 @@ import { getCurrencySymbol } from '@angular/common'; import { ChangeDetectionStrategy, Component, Input, OnDestroy, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; -import { FormlyConfig, FormlyFieldConfig } from '@ngx-formly/core'; +import { FormlyFieldConfig } from '@ngx-formly/core'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; @@ -37,7 +37,7 @@ export class UserBudgetFormComponent implements OnInit, OnDestroy { private destroy$ = new Subject(); - constructor(private appFacade: AppFacade, private config: FormlyConfig) {} + constructor(private appFacade: AppFacade) {} ngOnInit() { if (!this.form) { @@ -84,8 +84,8 @@ export class UserBudgetFormComponent implements OnInit, OnDestroy { { key: 'orderSpentLimitValue', type: 'ish-text-input-field', - wrappers: [...(this.config.getType('ish-text-input-field').wrappers ?? []), 'input-addon'], templateOptions: { + postWrappers: ['input-addon'], label: 'account.user.new.order_spend_limit.label', addonLeft: { text: getCurrencySymbol(this.model.currency, 'wide', this.currentLocale.lang), @@ -107,8 +107,8 @@ export class UserBudgetFormComponent implements OnInit, OnDestroy { className: 'col-8', key: 'budgetValue', type: 'ish-text-input-field', - wrappers: [...(this.config.getType('ish-text-input-field').wrappers ?? []), 'input-addon'], templateOptions: { + postWrappers: ['input-addon'], labelClass: 'col-md-6', fieldClass: 'col-md-6 pr-0', label: 'account.user.budget.label', diff --git a/src/app/pages/registration/registration-page.component.spec.ts b/src/app/pages/registration/registration-page.component.spec.ts index 21732af8e1..fc981de5e4 100644 --- a/src/app/pages/registration/registration-page.component.spec.ts +++ b/src/app/pages/registration/registration-page.component.spec.ts @@ -3,10 +3,10 @@ import { Component } from '@angular/core'; import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; import { ReactiveFormsModule } from '@angular/forms'; import { RouterTestingModule } from '@angular/router/testing'; -import { FormlyConfig, FormlyForm } from '@ngx-formly/core'; +import { FormlyForm } from '@ngx-formly/core'; import { TranslateModule } from '@ngx-translate/core'; import { MockComponent } from 'ng-mocks'; -import { anything, instance, mock, when } from 'ts-mockito'; +import { instance, mock } from 'ts-mockito'; import { AccountFacade } from 'ish-core/facades/account.facade'; import { FeatureToggleService } from 'ish-core/feature-toggle.module'; @@ -19,12 +19,10 @@ describe('Registration Page Component', () => { let component: RegistrationPageComponent; let element: HTMLElement; let location: Location; - let formlyConfig: FormlyConfig; @Component({ template: 'dummy' }) class DummyComponent {} beforeEach(async () => { - formlyConfig = mock(FormlyConfig); await TestBed.configureTestingModule({ declarations: [ DummyComponent, @@ -39,7 +37,6 @@ describe('Registration Page Component', () => { ], providers: [ { provide: AccountFacade, useFactory: () => instance(mock(AccountFacade)) }, - { provide: FormlyConfig, useFactory: () => instance(formlyConfig) }, { provide: FeatureToggleService, useFactory: () => instance(mock(FeatureToggleService)) }, ], }).compileComponents(); @@ -51,8 +48,6 @@ describe('Registration Page Component', () => { fixture = TestBed.createComponent(RegistrationPageComponent); component = fixture.componentInstance; element = fixture.nativeElement; - - when(formlyConfig.getType(anything())).thenReturn({ name: '', wrappers: [] }); }); it('should be created', () => { diff --git a/src/app/pages/registration/registration-page.component.ts b/src/app/pages/registration/registration-page.component.ts index f4cb64e704..1afb2b6a46 100644 --- a/src/app/pages/registration/registration-page.component.ts +++ b/src/app/pages/registration/registration-page.component.ts @@ -1,7 +1,7 @@ import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; import { FormGroup, Validators } from '@angular/forms'; import { Router } from '@angular/router'; -import { FormlyConfig, FormlyFieldConfig } from '@ngx-formly/core'; +import { FormlyFieldConfig } from '@ngx-formly/core'; import { UUID } from 'angular2-uuid'; import { Observable } from 'rxjs'; @@ -28,8 +28,7 @@ export class RegistrationPageComponent implements OnInit { constructor( private accountFacade: AccountFacade, private router: Router, - private featureToggle: FeatureToggleService, - private config: FormlyConfig + private featureToggle: FeatureToggleService ) {} submitted = false; @@ -208,8 +207,8 @@ export class RegistrationPageComponent implements OnInit { { key: 'password', type: 'ish-password-field', - wrappers: [...this.config.getType('ish-password-field').wrappers, 'description'], templateOptions: { + postWrappers: ['description'], required: true, label: 'account.register.password.label', customDescription: { diff --git a/src/app/shared/formly-address-forms/configurations/us/address-form-us.configuration.ts b/src/app/shared/formly-address-forms/configurations/us/address-form-us.configuration.ts index 42f9fffc60..c7fa55544d 100644 --- a/src/app/shared/formly-address-forms/configurations/us/address-form-us.configuration.ts +++ b/src/app/shared/formly-address-forms/configurations/us/address-form-us.configuration.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; import { Validators } from '@angular/forms'; -import { FormlyConfig, FormlyFieldConfig } from '@ngx-formly/core'; +import { FormlyFieldConfig } from '@ngx-formly/core'; import { pick } from 'lodash-es'; import { map } from 'rxjs/operators'; @@ -15,7 +15,7 @@ import { export class AddressFormUSConfiguration extends AddressFormConfiguration { countryCode = 'US'; - constructor(private appFacade: AppFacade, private config: FormlyConfig) { + constructor(private appFacade: AppFacade) { super(); } @@ -44,8 +44,8 @@ export class AddressFormUSConfiguration extends AddressFormConfiguration { { key: 'city', type: 'ish-text-input-field', - wrappers: [...this.config.getType('ish-text-input-field').wrappers, 'tooltip'], templateOptions: { + postWrappers: ['tooltip'], label: 'account.default_address.city.label', required: true, tooltip: { diff --git a/src/app/shared/formly/extensions/post-wrappers-extension.ts b/src/app/shared/formly/extensions/post-wrappers-extension.ts new file mode 100644 index 0000000000..3ec2d57e68 --- /dev/null +++ b/src/app/shared/formly/extensions/post-wrappers-extension.ts @@ -0,0 +1,24 @@ +import { FormlyConfig, FormlyExtension, FormlyFieldConfig, FormlyTemplateOptions } from '@ngx-formly/core'; + +class PostWrappersExtension implements FormlyExtension { + constructor(private formlyConfig: FormlyConfig) {} + + prePopulate(field: FormlyFieldConfig): void { + const to: FormlyTemplateOptions & { postWrappers?: string[] } = field.templateOptions; + if (!to?.postWrappers || to.postWrappers.length === 0) { + return; + } + field.wrappers = [...(this.formlyConfig.getType(field.type)?.wrappers ?? []), ...to.postWrappers]; + } +} + +export function registerPostWrappersExtension(formlyConfig: FormlyConfig) { + return { + extensions: [ + { + name: 'post-wrappers', + extension: new PostWrappersExtension(formlyConfig), + }, + ], + }; +} diff --git a/src/app/shared/formly/formly.module.ts b/src/app/shared/formly/formly.module.ts index c46d704966..5488d63aa2 100644 --- a/src/app/shared/formly/formly.module.ts +++ b/src/app/shared/formly/formly.module.ts @@ -2,7 +2,7 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { ReactiveFormsModule } from '@angular/forms'; import { NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap'; -import { FORMLY_CONFIG, FormlyModule as FormlyBaseModule } from '@ngx-formly/core'; +import { FORMLY_CONFIG, FormlyConfig, FormlyModule as FormlyBaseModule } from '@ngx-formly/core'; import { FormlySelectModule } from '@ngx-formly/core/select'; import { TranslateModule, TranslateService } from '@ngx-translate/core'; @@ -16,6 +16,7 @@ import { ValidationIconsComponent } from './components/validation-icons/validati import { ValidationMessageComponent } from './components/validation-message/validation-message.component'; import { criticalDefaultValuesExtension } from './extensions/critical-default-values.extension'; import { hideIfEmptyOptionsExtension } from './extensions/hide-if-empty-options.extension'; +import { registerPostWrappersExtension } from './extensions/post-wrappers-extension'; import { registerTranslateSelectOptionsExtension } from './extensions/translate-select-options.extension'; import { CaptchaFieldComponent } from './types/captcha-field/captcha-field.component'; import { CheckboxFieldComponent } from './types/checkbox-field/checkbox-field.component'; @@ -132,6 +133,12 @@ import { ValidationWrapperComponent } from './wrappers/validation-wrapper/valida useFactory: registerTranslateSelectOptionsExtension, deps: [TranslateService], }, + { + provide: FORMLY_CONFIG, + multi: true, + useFactory: registerPostWrappersExtension, + deps: [FormlyConfig], + }, ], exports: [ CaptchaFieldComponent,