diff --git a/docs/guides/formly.md b/docs/guides/formly.md index 0f5743446c..4d443d1d5a 100644 --- a/docs/guides/formly.md +++ b/docs/guides/formly.md @@ -230,7 +230,7 @@ You can find a simple example of a custom type test in [text-input.field.compone To test custom wrappers, create a `FormlyTestingContainerComponent` component, configure the `FormlyModule` with an example type (for example `FormlyTestingExampleComponent`) and the wrapper and set an appropriate testing configuration. -You can find a simple example of a wrapper test in [textarea-description-wrapper.component.spec.ts](../../src/app/shared/formly/wrappers/textarea-description-wrapper/textarea-description-wrapper.component.spec.ts). +You can find a simple example of a wrapper test in [maxlength-description-wrapper.component.spec.ts](../../src/app/shared/formly/wrappers/maxlength-description-wrapper/maxlength-description-wrapper.component.spec.ts). ## How to Configure Formly @@ -273,15 +273,15 @@ Refer to the tables below for an overview of these parts. ### Wrappers -| Name | Functionality | Relevant props | -| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| form-field-horizontal | Adds a label next to the field and adds red styling for invalid fields. | `labelClass`& `fieldClass`: Classes that will be added to the label or field `
` | -| form-field-checkbox-horizontal | Adds a label for a checkbox or radio field, adds red styling and error messages for invalid fields. Adds a title for a checkbox, if provided. Uses `validators.validation` and `validation.messages` properties. Adds a tooltip behind the label, see also tooltip-wrapper | `labelClass`, `titleClass`& `fieldClass`: Classes that will be added to the label, title or the outer field `
` | -| validation | Adds validation icons and error messages to the field. Uses `validators.validation` and `validation.messages` properties. | `showValidation`: `(field: FormlyFieldConfig) => boolean`: optional, used to determine whether to show validation check marks | -| textarea-description | Adds a description to textarea fields, including the amount of remaining characters. | `maxLength`: Specifies the maximum length to be displayed in the message. `customDescription`: translation key for the textarea description (default: 'textarea.max_limit' ) | -| description | Adds a custom description to any field | `customDescription`: `string` or `{key: string; args: any}` that will be translated | -| tooltip | Adds a tooltip to a field. Includes `` component. | `tooltip`: `{ title?: string; text: string; link: string }` that defines the different tooltip texts. | -| input-addon | Adds a prepended or appended text to a field, e.g. a currency or unit. | `addonLeft?`: `{ text: string \| Observable; }, addonRight?: {text: string \| Observable}` that defines the addon texts. | +| Name | Functionality | Relevant props | +| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| form-field-horizontal | Adds a label next to the field and adds red styling for invalid fields. | `labelClass`& `fieldClass`: Classes that will be added to the label or field `
` | +| form-field-checkbox-horizontal | Adds a label for a checkbox or radio field, adds red styling and error messages for invalid fields. Adds a title for a checkbox, if provided. Uses `validators.validation` and `validation.messages` properties. Adds a tooltip behind the label, see also tooltip-wrapper | `labelClass`, `titleClass`& `fieldClass`: Classes that will be added to the label, title or the outer field `
` | +| validation | Adds validation icons and error messages to the field. Uses `validators.validation` and `validation.messages` properties. | `showValidation`: `(field: FormlyFieldConfig) => boolean`: optional, used to determine whether to show validation check marks | +| maxlength-description | Adds a description to textarea fields, including the amount of remaining characters (added to textarea by default, can be used for other fields as well). | `maxLength`: Specifies the maximum length to be displayed in the message (required). `maxLengthDescription`: translation key for the maxlength description (default: 'textarea.max_limit' ) | +| description | Adds a custom description to any field | `customDescription`: `string` or `{key: string; args: any}` that will be translated | +| tooltip | Adds a tooltip to a field. Includes `` component. | `tooltip`: `{ title?: string; text: string; link: string }` that defines the different tooltip texts. | +| input-addon | Adds a prepended or appended text to a field, e.g. a currency or unit. | `addonLeft?`: `{ text: string \| Observable; }, addonRight?: {text: string \| Observable}` that defines the addon texts. | ### Extensions diff --git a/docs/guides/migrations.md b/docs/guides/migrations.md index ec9017f0aa..336e64a183 100644 --- a/docs/guides/migrations.md +++ b/docs/guides/migrations.md @@ -47,6 +47,16 @@ For that reason product variations are now loaded lazily through the following c - The `productMaster` property on the product view model has been removed. The master product should be individually retrieved. - The `ish-product-item-variations` component has been refactored. +The Formly wrapper `textarea-description` was renamed to the better suited name `maxlength-description` and the rendering logic and compatibility to the general `description` wrapper was improved. +The renaming should better convey the fact that this wrapper can be used not only for `ish-textarea-field` (where it is configured by default) but with other input field types as well. +Besides this the main difference to the general `description` wrapper is its remaining `maxlength` calculation. +Together with the renaming the implementation was changed so that the description will only be rendered if the according field has a `props.maxLength` value configured. +And the `props` key to provide an alternative translation key was changed from `customDescription` to `maxLengthDescription`. +This change provides the possibility to use the `description` wrapper with its `customDescription` together with the `maxlength-description` wrapper with a customized `maxLengthDescription`. +For the migration of customer projects it needs to be checked whether a `customDescription` is configured for a `ish-textarea-field` and if so it needs to be replaced with `maxLengthDescription`. +Additionally it needs to be checked if the `textarea-description` wrapper is configured anywhere else then the default assignment to the `ish-textarea-field`. +If so these wrapper configurations need to be replaced with `maxlength-description`. + ## From 5.0 to 5.1 The OrderListComponent is strictly presentational, components using it have to supply the data. diff --git a/src/app/extensions/rating/shared/product-review-create-dialog/product-review-create-dialog.component.ts b/src/app/extensions/rating/shared/product-review-create-dialog/product-review-create-dialog.component.ts index 2c9585e869..e2c325984e 100644 --- a/src/app/extensions/rating/shared/product-review-create-dialog/product-review-create-dialog.component.ts +++ b/src/app/extensions/rating/shared/product-review-create-dialog/product-review-create-dialog.component.ts @@ -92,10 +92,10 @@ export class ProductReviewCreateDialogComponent implements OnInit { labelClass: 'col-md-3', fieldClass: 'col-md-9', required: true, - maxLength: 4000, rows: 5, placeholder: 'product.review.content.placeholder', - customDescription: 'product.review.content.max_limit', + maxLength: 4000, + maxLengthDescription: 'product.review.content.max_limit', }, validation: { messages: { diff --git a/src/app/shared/components/basket/basket-merchant-message/basket-merchant-message.component.ts b/src/app/shared/components/basket/basket-merchant-message/basket-merchant-message.component.ts index 4b46a87962..d1f9f0a49f 100644 --- a/src/app/shared/components/basket/basket-merchant-message/basket-merchant-message.component.ts +++ b/src/app/shared/components/basket/basket-merchant-message/basket-merchant-message.component.ts @@ -40,7 +40,6 @@ export class BasketMerchantMessageComponent implements OnInit, OnChanges { key: 'messageToMerchant', type: 'ish-textarea-field', props: { - postWrappers: [{ wrapper: 'description', index: -1 }], label: 'checkout.basket_merchant_message.label', maxLength: 1000, rows: 2, diff --git a/src/app/shared/formly/dev/testing/formly-testing.module.ts b/src/app/shared/formly/dev/testing/formly-testing.module.ts index 54f139ca17..0a26c983cb 100644 --- a/src/app/shared/formly/dev/testing/formly-testing.module.ts +++ b/src/app/shared/formly/dev/testing/formly-testing.module.ts @@ -192,7 +192,7 @@ class RepeatFieldComponent extends FieldArrayType {} wrappers: [ { name: 'form-field-horizontal', component: DummyWrapperComponent }, { name: 'form-field-checkbox-horizontal', component: DummyWrapperComponent }, - { name: 'textarea-description', component: DummyWrapperComponent }, + { name: 'maxlength-description', component: DummyWrapperComponent }, { name: 'tooltip', component: DummyWrapperComponent }, { name: 'validation', component: DummyWrapperComponent }, { name: 'description', component: DummyWrapperComponent }, diff --git a/src/app/shared/formly/types/textarea-field/textarea-field.component.ts b/src/app/shared/formly/types/textarea-field/textarea-field.component.ts index 71d5e14ba3..90ef1e13d7 100644 --- a/src/app/shared/formly/types/textarea-field/textarea-field.component.ts +++ b/src/app/shared/formly/types/textarea-field/textarea-field.component.ts @@ -8,10 +8,10 @@ import { FieldType, FieldTypeConfig } from '@ngx-formly/core'; * @props **cols** - the amount of columns the textarea should have * @props **rows** - the amount of rows the textarea should have * - * @defaultWrappers form-field-horizontal & textarea-description & validation + * @defaultWrappers form-field-horizontal & maxlength-description & validation * * @usageNotes - * See the textarea-description wrapper for more info on the relevant props. + * See the maxlength-description wrapper for more info on the relevant props. */ @Component({ selector: 'ish-textarea-field', diff --git a/src/app/shared/formly/types/types.module.ts b/src/app/shared/formly/types/types.module.ts index 14f9220773..6d38fbea0a 100644 --- a/src/app/shared/formly/types/types.module.ts +++ b/src/app/shared/formly/types/types.module.ts @@ -139,7 +139,7 @@ const fieldComponents = [ { name: 'ish-textarea-field', component: TextareaFieldComponent, - wrappers: ['form-field-horizontal', 'textarea-description', 'validation'], + wrappers: ['form-field-horizontal', 'maxlength-description', 'validation'], }, { name: 'ish-checkbox-field', diff --git a/src/app/shared/formly/wrappers/maxlength-description-wrapper/maxlength-description-wrapper.component.html b/src/app/shared/formly/wrappers/maxlength-description-wrapper/maxlength-description-wrapper.component.html new file mode 100644 index 0000000000..1482c09ea6 --- /dev/null +++ b/src/app/shared/formly/wrappers/maxlength-description-wrapper/maxlength-description-wrapper.component.html @@ -0,0 +1,4 @@ + + + {{ desc }} + diff --git a/src/app/shared/formly/wrappers/textarea-description-wrapper/textarea-description-wrapper.component.spec.ts b/src/app/shared/formly/wrappers/maxlength-description-wrapper/maxlength-description-wrapper.component.spec.ts similarity index 77% rename from src/app/shared/formly/wrappers/textarea-description-wrapper/textarea-description-wrapper.component.spec.ts rename to src/app/shared/formly/wrappers/maxlength-description-wrapper/maxlength-description-wrapper.component.spec.ts index 064eec86f0..ceb534b4fc 100644 --- a/src/app/shared/formly/wrappers/textarea-description-wrapper/textarea-description-wrapper.component.spec.ts +++ b/src/app/shared/formly/wrappers/maxlength-description-wrapper/maxlength-description-wrapper.component.spec.ts @@ -7,9 +7,9 @@ import { FormlyTestingComponentsModule } from 'ish-shared/formly/dev/testing/for import { FormlyTestingContainerComponent } from 'ish-shared/formly/dev/testing/formly-testing-container/formly-testing-container.component'; import { FormlyTestingExampleComponent } from 'ish-shared/formly/dev/testing/formly-testing-example/formly-testing-example.component'; -import { TextareaDescriptionWrapperComponent } from './textarea-description-wrapper.component'; +import { MaxlengthDescriptionWrapperComponent } from './maxlength-description-wrapper.component'; -describe('Textarea Description Wrapper Component', () => { +describe('Maxlength Description Wrapper Component', () => { let component: FormlyTestingContainerComponent; let fixture: ComponentFixture; let element: HTMLElement; @@ -21,12 +21,12 @@ describe('Textarea Description Wrapper Component', () => { imports: [ FormlyModule.forRoot({ types: [{ name: 'textarea', component: FormlyTestingExampleComponent }], - wrappers: [{ name: 'textarea-description-wrapper', component: TextareaDescriptionWrapperComponent }], + wrappers: [{ name: 'maxlength-description-wrapper', component: MaxlengthDescriptionWrapperComponent }], }), FormlyTestingComponentsModule, TranslateModule.forRoot(), ], - declarations: [TextareaDescriptionWrapperComponent], + declarations: [MaxlengthDescriptionWrapperComponent], }).compileComponents(); }); @@ -44,7 +44,7 @@ describe('Textarea Description Wrapper Component', () => { { key: 'textarea', type: 'textarea', - wrappers: ['textarea-description-wrapper'], + wrappers: ['maxlength-description-wrapper'], props: { maxLength: 1000, }, @@ -65,13 +65,13 @@ describe('Textarea Description Wrapper Component', () => { it('should be rendered after creation', () => { fixture.detectChanges(); - expect(element.querySelector('ish-textarea-description-wrapper')).toBeTruthy(); + expect(element.querySelector('ish-maxlength-description-wrapper')).toBeTruthy(); }); it('should display maxLength on empty field', () => { component.form.get('textarea')?.setValue(''); fixture.detectChanges(); - expect(element.querySelector('[data-testing-id="textarea-description"]')?.textContent.trim()).toEqual('1000'); + expect(element.querySelector('[data-testing-id="maxlength-description"]')?.textContent.trim()).toEqual('1000'); }); it('should display correct remaining length if field is not empty', fakeAsync(() => { @@ -79,6 +79,6 @@ describe('Textarea Description Wrapper Component', () => { component.form.get('textarea')?.setValue('0123456789'); tick(1000); fixture.detectChanges(); - expect(element.querySelector('[data-testing-id="textarea-description"]')?.textContent.trim()).toEqual('990'); + expect(element.querySelector('[data-testing-id="maxlength-description"]')?.textContent.trim()).toEqual('990'); })); }); diff --git a/src/app/shared/formly/wrappers/textarea-description-wrapper/textarea-description-wrapper.component.ts b/src/app/shared/formly/wrappers/maxlength-description-wrapper/maxlength-description-wrapper.component.ts similarity index 53% rename from src/app/shared/formly/wrappers/textarea-description-wrapper/textarea-description-wrapper.component.ts rename to src/app/shared/formly/wrappers/maxlength-description-wrapper/maxlength-description-wrapper.component.ts index 628dc30623..a5043e1336 100644 --- a/src/app/shared/formly/wrappers/textarea-description-wrapper/textarea-description-wrapper.component.ts +++ b/src/app/shared/formly/wrappers/maxlength-description-wrapper/maxlength-description-wrapper.component.ts @@ -1,23 +1,24 @@ import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; import { FieldWrapper } from '@ngx-formly/core'; import { TranslateService } from '@ngx-translate/core'; -import { Observable } from 'rxjs'; +import { Observable, of } from 'rxjs'; import { startWith, switchMap, throttleTime } from 'rxjs/operators'; /** * Wrapper to display a description that counts the remaining characters in a field. * - * @props **maxLength** - will be used to determine the remaining available characters. + * @props **maxLength** - will be used to determine the remaining available characters (required, otherwise the counter description will not be rendered). + * @props **maxLengthDescription** - an alternative translation key that can be used to customize the counter description (default: 'textarea.max_limit'). * * @usageNotes - * This wrapper is made for the textarea type but could be used for different field types as well. + * This wrapper is made for the textarea type (and assigned to 'ish-textarea-field' by default) but could be used for different field types as well. */ @Component({ - selector: 'ish-textarea-description-wrapper', - templateUrl: './textarea-description-wrapper.component.html', + selector: 'ish-maxlength-description-wrapper', + templateUrl: './maxlength-description-wrapper.component.html', changeDetection: ChangeDetectionStrategy.Default, }) -export class TextareaDescriptionWrapperComponent extends FieldWrapper implements OnInit { +export class MaxlengthDescriptionWrapperComponent extends FieldWrapper implements OnInit { description$: Observable; constructor(private translate: TranslateService) { @@ -33,8 +34,10 @@ export class TextareaDescriptionWrapperComponent extends FieldWrapper implements } private getDescription$(value: string): Observable { - return this.translate.get(this.props.customDescription ?? 'textarea.max_limit', { - 0: Math.max(0, this.props.maxLength - (value?.length ?? 0)), - }); + return this.props.maxLength + ? this.translate.get(this.props.maxLengthDescription ?? 'textarea.max_limit', { + 0: Math.max(0, this.props.maxLength - (value?.length ?? 0)), + }) + : of(undefined); } } diff --git a/src/app/shared/formly/wrappers/textarea-description-wrapper/textarea-description-wrapper.component.html b/src/app/shared/formly/wrappers/textarea-description-wrapper/textarea-description-wrapper.component.html deleted file mode 100644 index 44d8c38931..0000000000 --- a/src/app/shared/formly/wrappers/textarea-description-wrapper/textarea-description-wrapper.component.html +++ /dev/null @@ -1,6 +0,0 @@ - -
- - {{ desc }} - -
diff --git a/src/app/shared/formly/wrappers/wrappers.module.ts b/src/app/shared/formly/wrappers/wrappers.module.ts index a601eabfda..a08961c478 100644 --- a/src/app/shared/formly/wrappers/wrappers.module.ts +++ b/src/app/shared/formly/wrappers/wrappers.module.ts @@ -10,7 +10,7 @@ import { DescriptionWrapperComponent } from './description-wrapper/description-w import { HorizontalCheckboxWrapperComponent } from './horizontal-checkbox-wrapper/horizontal-checkbox-wrapper.component'; import { HorizontalWrapperComponent } from './horizontal-wrapper/horizontal-wrapper.component'; import { InputAddonWrapperComponent } from './input-addon-wrapper/input-addon-wrapper.component'; -import { TextareaDescriptionWrapperComponent } from './textarea-description-wrapper/textarea-description-wrapper.component'; +import { MaxlengthDescriptionWrapperComponent } from './maxlength-description-wrapper/maxlength-description-wrapper.component'; import { TooltipWrapperComponent } from './tooltip-wrapper/tooltip-wrapper.component'; import { ValidationWrapperComponent } from './validation-wrapper/validation-wrapper.component'; @@ -19,7 +19,7 @@ const wrapperComponents = [ HorizontalCheckboxWrapperComponent, HorizontalWrapperComponent, InputAddonWrapperComponent, - TextareaDescriptionWrapperComponent, + MaxlengthDescriptionWrapperComponent, TooltipWrapperComponent, ValidationWrapperComponent, ]; @@ -35,7 +35,7 @@ const wrapperComponents = [ { name: 'form-field-horizontal', component: HorizontalWrapperComponent }, { name: 'form-field-checkbox-horizontal', component: HorizontalCheckboxWrapperComponent }, { name: 'input-addon', component: InputAddonWrapperComponent }, - { name: 'textarea-description', component: TextareaDescriptionWrapperComponent }, + { name: 'maxlength-description', component: MaxlengthDescriptionWrapperComponent }, { name: 'tooltip', component: TooltipWrapperComponent }, { name: 'validation', component: ValidationWrapperComponent }, { name: 'description', component: DescriptionWrapperComponent },