mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2026-09-09 18:03:21 +00:00
AAE-37713 Amount locale display v.2 (#11319)
* [AAE-37713] amount widget formats value based on locale * [AAE-37713] added unit test with currency icon * [AAE-37713] provided amount widget config as observable * [AAE-37713] applied pr comments * [AAE-37713] subscribed amount widget to changes from form rules * [AAE-37713] applied pr comments * [AAE-37713] moved getLocale to service * [AAE-37713] moved getLocale to translation service
This commit is contained in:
@@ -12,7 +12,9 @@
|
||||
<div class="adf-amount-widget-container">
|
||||
<mat-form-field class="adf-amount-widget__input adf-form-field-input" [floatLabel]="placeholder ? 'always' : null">
|
||||
@if ( (field.name || field?.required) && !field.leftLabels) { <mat-label class="adf-label" [attr.for]="field.id">{{field.name | translate }}</mat-label> }
|
||||
<span matTextPrefix class="adf-amount-widget__prefix-spacing">{{ currency }} </span>
|
||||
@if(!enableDisplayBasedOnLocale) {
|
||||
<span matTextPrefix class="adf-amount-widget__prefix-spacing">{{ currency }} </span>
|
||||
}
|
||||
<input
|
||||
matInput
|
||||
[title]="field.tooltip"
|
||||
@@ -21,12 +23,13 @@
|
||||
[id]="field.id"
|
||||
[required]="field.required && field.isVisible"
|
||||
[placeholder]="placeholder"
|
||||
[value]="field.value"
|
||||
[(ngModel)]="field.value"
|
||||
(ngModelChange)="onFieldChanged(field)"
|
||||
[value]="amountWidgetValue"
|
||||
[(ngModel)]="amountWidgetValue"
|
||||
(ngModelChange)="onFieldChangedAmountWidget()"
|
||||
[disabled]="field.readOnly"
|
||||
(blur)="markAsTouched()"
|
||||
/>
|
||||
(focus)="amountWidgetOnFocus()"
|
||||
(blur)="amountWidgetOnBlur()"
|
||||
/>
|
||||
</mat-form-field>
|
||||
<div class="adf-error-messages-container">
|
||||
<error-widget [error]="field.validationSummary" />
|
||||
|
||||
@@ -23,6 +23,10 @@ import { FormModel } from '../core/form.model';
|
||||
import { HarnessLoader } from '@angular/cdk/testing';
|
||||
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||
import { UnitTestingUtils } from '../../../../testing/unit-testing-utils';
|
||||
import { of } from 'rxjs';
|
||||
import { FormService } from '../../../services/form.service';
|
||||
import { FormFieldEvent } from '../../../events/form-field.event';
|
||||
import { TranslationService } from '../../../../translation/translation.service';
|
||||
|
||||
describe('AmountWidgetComponent', () => {
|
||||
let loader: HarnessLoader;
|
||||
@@ -32,8 +36,10 @@ describe('AmountWidgetComponent', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [AmountWidgetComponent]
|
||||
imports: [AmountWidgetComponent],
|
||||
providers: [{ provide: TranslationService, useValue: { getLocale: () => 'en-US' } }]
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(AmountWidgetComponent);
|
||||
widget = fixture.componentInstance;
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
@@ -94,6 +100,109 @@ describe('AmountWidgetComponent', () => {
|
||||
expect(widget.placeholder).toBe('1234');
|
||||
});
|
||||
|
||||
it('it should return locale based on browser', () => {
|
||||
const expectedLanguage = 'en-US';
|
||||
widget.enableDisplayBasedOnLocale = true;
|
||||
widget.field = new FormFieldModel(null, { id: 1, name: 'test', value: 25, currency: 'USD' });
|
||||
widget.setInitialValues();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(widget.locale).toBe(expectedLanguage);
|
||||
});
|
||||
|
||||
it('should set initial values when enableDisplayBasedOnLocale is enabled', () => {
|
||||
widget.field = new FormFieldModel(null, { id: 1, name: 'test', value: 25, currency: 'USD' });
|
||||
widget.enableDisplayBasedOnLocale = true;
|
||||
widget.currency = 'USD';
|
||||
widget.setInitialValues();
|
||||
|
||||
expect(widget.amountWidgetValue).toBe('$25');
|
||||
expect(widget.decimalProperty).toBe('1.0-0');
|
||||
expect(widget.valueAsNumber).toBe(25);
|
||||
});
|
||||
|
||||
it('should set initial values with correct currency', () => {
|
||||
widget.field = new FormFieldModel(null, { id: 2, name: 'test', value: 25, currency: 'GBP' });
|
||||
widget.enableDisplayBasedOnLocale = true;
|
||||
widget.currency = 'GBP';
|
||||
widget.setInitialValues();
|
||||
|
||||
expect(widget.amountWidgetValue).toBe('£25');
|
||||
expect(widget.decimalProperty).toBe('1.0-0');
|
||||
});
|
||||
|
||||
it('should set initial values with correct currency icon', () => {
|
||||
widget.field = new FormFieldModel(null, { id: 2, name: 'test', value: 25, currency: '¥' });
|
||||
widget.enableDisplayBasedOnLocale = true;
|
||||
widget.currency = '¥';
|
||||
widget.setInitialValues();
|
||||
|
||||
expect(widget.amountWidgetValue).toBe('¥25');
|
||||
expect(widget.decimalProperty).toBe('1.0-0');
|
||||
});
|
||||
|
||||
it('should set initial values without currency', () => {
|
||||
widget.field = new FormFieldModel(null, { id: 3, name: 'test', value: 25, currency: '' });
|
||||
widget.enableDisplayBasedOnLocale = true;
|
||||
widget.currency = '';
|
||||
widget.currencyDisplay = '';
|
||||
widget.setInitialValues();
|
||||
|
||||
expect(widget.amountWidgetValue).toBe('25');
|
||||
expect(widget.decimalProperty).toBe('1.0-0');
|
||||
});
|
||||
|
||||
it('should set initial values when enableDisplayBasedOnLocale is disabled', () => {
|
||||
widget.field = new FormFieldModel(null, { id: 4, name: 'test', value: 25, enableFractions: false, className: '' });
|
||||
widget.enableDisplayBasedOnLocale = false;
|
||||
widget.setInitialValues();
|
||||
|
||||
expect(widget.amountWidgetValue.toString()).toBe('25');
|
||||
});
|
||||
|
||||
it('should transform value from number to string', () => {
|
||||
widget.enableDisplayBasedOnLocale = true;
|
||||
widget.valueAsNumber = 123456;
|
||||
widget.amountWidgetOnFocus();
|
||||
expect(widget.amountWidgetValue).toBe('123456');
|
||||
|
||||
widget.valueAsNumber = 123456.11;
|
||||
widget.amountWidgetOnFocus();
|
||||
expect(widget.amountWidgetValue).toBe('123456.11');
|
||||
|
||||
widget.valueAsNumber = 0;
|
||||
widget.amountWidgetOnFocus();
|
||||
expect(widget.amountWidgetValue).toBe('0');
|
||||
|
||||
widget.valueAsNumber = undefined;
|
||||
widget.amountWidgetOnFocus();
|
||||
expect(widget.amountWidgetValue).toBe(null);
|
||||
});
|
||||
|
||||
it('should update field.value on change', () => {
|
||||
widget.field = new FormFieldModel(null, { id: 5, name: 'test', value: 25 });
|
||||
const mockValue = '1234.12';
|
||||
widget.amountWidgetValue = mockValue;
|
||||
widget.onFieldChangedAmountWidget();
|
||||
|
||||
expect(widget.field.value).toBe(mockValue);
|
||||
});
|
||||
|
||||
it('should transform values on blur', () => {
|
||||
widget.enableDisplayBasedOnLocale = true;
|
||||
widget.amountWidgetValue = '1234.56';
|
||||
widget.amountWidgetOnBlur();
|
||||
|
||||
expect(widget.valueAsNumber).toBe(1234.56);
|
||||
expect(widget.amountWidgetValue).toBe('$1,234.56');
|
||||
|
||||
widget.amountWidgetValue = '';
|
||||
widget.amountWidgetOnBlur();
|
||||
|
||||
expect(widget.valueAsNumber).toBe(null);
|
||||
expect(widget.amountWidgetValue).toBe(null);
|
||||
});
|
||||
|
||||
describe('when tooltip is set', () => {
|
||||
beforeEach(() => {
|
||||
widget.field = new FormFieldModel(new FormModel({ taskId: '<id>' }), {
|
||||
@@ -145,6 +254,7 @@ describe('AmountWidgetComponent - rendering', () => {
|
||||
let widget: AmountWidgetComponent;
|
||||
let fixture: ComponentFixture<AmountWidgetComponent>;
|
||||
let testingUtils: UnitTestingUtils;
|
||||
let formService: FormService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
@@ -154,6 +264,7 @@ describe('AmountWidgetComponent - rendering', () => {
|
||||
widget = fixture.componentInstance;
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
testingUtils = new UnitTestingUtils(fixture.debugElement, loader);
|
||||
formService = TestBed.inject(FormService);
|
||||
});
|
||||
|
||||
it('[C289915] - Should be able to display different currency icons', async () => {
|
||||
@@ -345,6 +456,311 @@ describe('AmountWidgetComponent - rendering', () => {
|
||||
expect(asterisk.textContent).toEqual('*');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test widget with ADF_AMOUNT_SETTINGS as observable', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.resetTestingModule();
|
||||
});
|
||||
|
||||
describe('set module for enableDisplayBasedOnLocale = true', () => {
|
||||
const mockField = new FormFieldModel(new FormModel(), {
|
||||
id: 'TestAmount1',
|
||||
name: 'Test Amount',
|
||||
type: 'amount',
|
||||
currency: 'USD',
|
||||
enableFractions: true,
|
||||
value: '1234.55'
|
||||
});
|
||||
beforeEach(async () => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [AmountWidgetComponent],
|
||||
providers: [
|
||||
{ provide: ADF_AMOUNT_SETTINGS, useValue: of({ enableDisplayBasedOnLocale: true }) },
|
||||
{ provide: TranslationService, useValue: { getLocale: () => 'en-US' } }
|
||||
]
|
||||
});
|
||||
fixture = TestBed.createComponent(AmountWidgetComponent);
|
||||
widget = fixture.componentInstance;
|
||||
fixture.componentRef.setInput('field', mockField);
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
testingUtils = new UnitTestingUtils(fixture.debugElement, loader);
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should set enableDisplayBasedOnLocale to true', () => {
|
||||
expect(widget.enableDisplayBasedOnLocale).toBeTrue();
|
||||
expect(widget.decimalProperty).toBe('1.2-2');
|
||||
expect(widget.locale).toBe('en-US');
|
||||
expect(widget.valueAsNumber).toBe('1234.55');
|
||||
expect(widget.amountWidgetValue).toBe('$1,234.55');
|
||||
});
|
||||
|
||||
it('should not display prefix with currency when enableDisplayBasedOnLocale = true', async () => {
|
||||
const field = await testingUtils.getMatFormField();
|
||||
expect(await field.getPrefixText()).toBe('');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('AmountWidgetComponent - subscribeToFieldChanges', () => {
|
||||
it('should subscribe to formFieldValueChanged events for the specific field', () => {
|
||||
const mockField = new FormFieldModel(new FormModel(), {
|
||||
id: 'amount-1',
|
||||
name: 'Test Amount',
|
||||
type: 'amount',
|
||||
value: '100'
|
||||
});
|
||||
const subscriptionSpy = spyOn(formService.formFieldValueChanged, 'subscribe').and.callThrough();
|
||||
widget.field = mockField;
|
||||
widget.subscribeToFieldChanges();
|
||||
|
||||
expect(subscriptionSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should update value when field value changes and input is not in focus with enableDisplayBasedOnLocale enabled', async () => {
|
||||
const mockField = new FormFieldModel(new FormModel(), {
|
||||
id: 'amount-1',
|
||||
name: 'Test Amount',
|
||||
type: 'amount',
|
||||
value: '100',
|
||||
currency: 'USD'
|
||||
});
|
||||
widget.field = mockField;
|
||||
widget.enableDisplayBasedOnLocale = true;
|
||||
widget.isInputInFocus = false;
|
||||
widget.currency = 'USD';
|
||||
widget.decimalProperty = '1.0-0';
|
||||
widget.ngOnInit();
|
||||
|
||||
const updateValueSpy = spyOn(widget, 'updateValue').and.callThrough();
|
||||
formService.formFieldValueChanged.next(new FormFieldEvent(mockField.form, { ...mockField, value: '200' } as FormFieldModel));
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(updateValueSpy).toHaveBeenCalledWith('200');
|
||||
expect(widget.amountWidgetValue).toBe('$200');
|
||||
});
|
||||
|
||||
it('should update amountWidgetValue when field value changes and input is not in focus with enableDisplayBasedOnLocale disabled', () => {
|
||||
const updateValueSpy = spyOn(widget, 'updateValue').and.callThrough();
|
||||
const mockField = new FormFieldModel(new FormModel(), {
|
||||
id: 'amount-1',
|
||||
name: 'Test Amount',
|
||||
type: 'amount',
|
||||
value: '100'
|
||||
});
|
||||
widget.field = mockField;
|
||||
widget.enableDisplayBasedOnLocale = false;
|
||||
widget.isInputInFocus = false;
|
||||
widget.ngOnInit();
|
||||
|
||||
formService.formFieldValueChanged.next(new FormFieldEvent(mockField.form, { ...mockField, value: '200' } as FormFieldModel));
|
||||
|
||||
expect(updateValueSpy).not.toHaveBeenCalled();
|
||||
expect(widget.amountWidgetValue).toBe('200');
|
||||
});
|
||||
|
||||
it('should not update value with formService.formFieldValueChanged when input is in focus', () => {
|
||||
const mockField = new FormFieldModel(new FormModel(), {
|
||||
id: 'amount-1',
|
||||
name: 'Test Amount',
|
||||
type: 'amount',
|
||||
value: '100'
|
||||
});
|
||||
widget.field = mockField;
|
||||
widget.enableDisplayBasedOnLocale = true;
|
||||
widget.isInputInFocus = true;
|
||||
widget.amountWidgetValue = '100';
|
||||
widget.ngOnInit();
|
||||
const updateValueSpy = spyOn(widget, 'updateValue');
|
||||
formService.formFieldValueChanged.next(new FormFieldEvent(mockField.form, { ...mockField, value: '200' } as FormFieldModel));
|
||||
|
||||
expect(updateValueSpy).not.toHaveBeenCalled();
|
||||
expect(widget.amountWidgetValue).toBe('100');
|
||||
});
|
||||
|
||||
it('should not react to events from different fields', () => {
|
||||
const mockField = new FormFieldModel(new FormModel(), {
|
||||
id: 'amount-1',
|
||||
name: 'Test Amount',
|
||||
type: 'amount',
|
||||
value: '100',
|
||||
enableFractions: false
|
||||
});
|
||||
const otherField = new FormFieldModel(new FormModel(), {
|
||||
id: 'amount-2',
|
||||
name: 'Other Amount',
|
||||
type: 'amount',
|
||||
value: '200'
|
||||
});
|
||||
widget.field = mockField;
|
||||
widget.currency = 'USD';
|
||||
widget.enableDisplayBasedOnLocale = true;
|
||||
widget.isInputInFocus = false;
|
||||
widget.amountWidgetValue = '100';
|
||||
widget.ngOnInit();
|
||||
|
||||
const updateValueSpy = spyOn(widget, 'updateValue').and.callThrough();
|
||||
|
||||
formService.formFieldValueChanged.next(new FormFieldEvent(otherField.form, otherField));
|
||||
|
||||
expect(updateValueSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should use field.value when updating without enableDisplayBasedOnLocale and input not in focus', () => {
|
||||
const mockField = new FormFieldModel(new FormModel(), {
|
||||
id: 'amount-1',
|
||||
name: 'Test Amount',
|
||||
type: 'amount',
|
||||
value: '100'
|
||||
});
|
||||
widget.field = mockField;
|
||||
widget.enableDisplayBasedOnLocale = false;
|
||||
widget.isInputInFocus = false;
|
||||
widget.ngOnInit();
|
||||
|
||||
mockField.value = '300';
|
||||
formService.formFieldValueChanged.next(new FormFieldEvent(mockField.form, mockField));
|
||||
|
||||
expect(widget.amountWidgetValue).toBe('300');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test widget with different setting for enableDisplayBasedOnLocale', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.resetTestingModule();
|
||||
});
|
||||
|
||||
describe('set module for enableDisplayBasedOnLocale = true', () => {
|
||||
const mockField = new FormFieldModel(new FormModel(), {
|
||||
id: 'TestAmount1',
|
||||
name: 'Test Amount',
|
||||
type: 'amount',
|
||||
currency: 'USD',
|
||||
enableFractions: true,
|
||||
value: '1234.55'
|
||||
});
|
||||
beforeEach(async () => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [AmountWidgetComponent],
|
||||
providers: [{ provide: ADF_AMOUNT_SETTINGS, useValue: { enableDisplayBasedOnLocale: true } }]
|
||||
});
|
||||
fixture = TestBed.createComponent(AmountWidgetComponent);
|
||||
widget = fixture.componentInstance;
|
||||
|
||||
fixture.componentRef.setInput('field', mockField);
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
testingUtils = new UnitTestingUtils(fixture.debugElement, loader);
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should not display prefix with currency when enableDisplayBasedOnLocale = true', async () => {
|
||||
const field = await testingUtils.getMatFormField();
|
||||
expect(await field.getPrefixText()).toBe('');
|
||||
});
|
||||
|
||||
it('should call method on focus and change input value', async () => {
|
||||
const focusSpy = spyOn(widget, 'amountWidgetOnFocus').and.callThrough();
|
||||
fixture.detectChanges();
|
||||
|
||||
const field = await testingUtils.getMatInput();
|
||||
const fieldValueBeforeFocus = await field.getValue();
|
||||
await field.focus();
|
||||
const fieldValue = await field.getValue();
|
||||
|
||||
expect(field).toBeDefined();
|
||||
expect(widget.field.value).toBe('1234.55');
|
||||
expect(fieldValueBeforeFocus).toBe('$1,234.55');
|
||||
expect(focusSpy).toHaveBeenCalled();
|
||||
expect(fieldValue).toBe('1234.55');
|
||||
});
|
||||
|
||||
it('should transform value on blur', async () => {
|
||||
const newValue = '456789';
|
||||
const blurSpy = spyOn(widget, 'amountWidgetOnBlur').and.callThrough();
|
||||
fixture.detectChanges();
|
||||
|
||||
const field = await testingUtils.getMatInput();
|
||||
const fieldValueBeforeBlur = await field.getValue();
|
||||
await field.setValue(newValue);
|
||||
await field.blur();
|
||||
const fieldValue = await field.getValue();
|
||||
|
||||
expect(field).toBeDefined();
|
||||
expect(widget.field.value).toBe(newValue);
|
||||
expect(fieldValueBeforeBlur).toBe('$1,234.55');
|
||||
expect(blurSpy).toHaveBeenCalled();
|
||||
expect(widget.valueAsNumber).toBe(parseFloat(newValue));
|
||||
expect(widget.amountWidgetValue).toBe('$456,789.00');
|
||||
expect(fieldValue).toBe('$456,789.00');
|
||||
});
|
||||
});
|
||||
describe('set module for enableDisplayBasedOnLocale = false', () => {
|
||||
const mockField = new FormFieldModel(new FormModel(), {
|
||||
id: 'TestAmount1',
|
||||
name: 'Test Amount',
|
||||
type: 'amount',
|
||||
currency: 'USD',
|
||||
enableFractions: true,
|
||||
value: '1234.55'
|
||||
});
|
||||
beforeEach(async () => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [AmountWidgetComponent],
|
||||
providers: [{ provide: ADF_AMOUNT_SETTINGS, useValue: { enableDisplayBasedOnLocale: false } }]
|
||||
});
|
||||
fixture = TestBed.createComponent(AmountWidgetComponent);
|
||||
widget = fixture.componentInstance;
|
||||
|
||||
fixture.componentRef.setInput('field', mockField);
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
testingUtils = new UnitTestingUtils(fixture.debugElement, loader);
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should display prefix with currency when enableDisplayBasedOnLocale = true', async () => {
|
||||
const field = await testingUtils.getMatFormField();
|
||||
expect(await field.getPrefixText()).toBe('USD');
|
||||
});
|
||||
|
||||
it('should call method on focus and not change input value', async () => {
|
||||
const focusSpy = spyOn(widget, 'amountWidgetOnFocus').and.callThrough();
|
||||
fixture.detectChanges();
|
||||
|
||||
const field = await testingUtils.getMatInput();
|
||||
const fieldValueBeforeFocus = await field.getValue();
|
||||
await field.focus();
|
||||
const fieldValue = await field.getValue();
|
||||
|
||||
expect(field).toBeDefined();
|
||||
expect(widget.field.value).toBe('1234.55');
|
||||
expect(widget.valueAsNumber).toBeUndefined();
|
||||
expect(fieldValueBeforeFocus).toBe('1234.55');
|
||||
expect(focusSpy).toHaveBeenCalled();
|
||||
expect(fieldValue).toBe('1234.55');
|
||||
});
|
||||
|
||||
it('should call method on blur and not change input value', async () => {
|
||||
const newValue = '456789';
|
||||
const blurSpy = spyOn(widget, 'amountWidgetOnBlur').and.callThrough();
|
||||
fixture.detectChanges();
|
||||
|
||||
const field = await testingUtils.getMatInput();
|
||||
const fieldValueBeforeBlur = await field.getValue();
|
||||
await field.setValue(newValue);
|
||||
await field.blur();
|
||||
const fieldValue = await field.getValue();
|
||||
|
||||
expect(field).toBeDefined();
|
||||
expect(widget.field.value).toBe(newValue);
|
||||
expect(widget.valueAsNumber).toBeUndefined();
|
||||
expect(fieldValueBeforeBlur).toBe('1234.55');
|
||||
expect(blurSpy).toHaveBeenCalled();
|
||||
expect(widget.valueAsNumber).toBeUndefined();
|
||||
expect(widget.amountWidgetValue).toBe('456789');
|
||||
expect(fieldValue).toBe('456789');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('AmountWidgetComponent settings', () => {
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
|
||||
/* eslint-disable @angular-eslint/component-selector */
|
||||
|
||||
import { NgIf } from '@angular/common';
|
||||
import { Component, OnInit, ViewEncapsulation, InjectionToken, Inject, Optional } from '@angular/core';
|
||||
import { CurrencyPipe, NgIf } from '@angular/common';
|
||||
import { Component, OnInit, ViewEncapsulation, InjectionToken, Inject, Optional, inject, DestroyRef } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
@@ -26,12 +26,17 @@ import { TranslatePipe } from '@ngx-translate/core';
|
||||
import { FormService } from '../../../services/form.service';
|
||||
import { ErrorWidgetComponent } from '../error/error.component';
|
||||
import { WidgetComponent } from '../widget.component';
|
||||
import { filter, isObservable, Observable } from 'rxjs';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { FormFieldEvent } from '../../../events/form-field.event';
|
||||
import { TranslationService } from '../../../../translation/translation.service';
|
||||
|
||||
export interface AmountWidgetSettings {
|
||||
showReadonlyPlaceholder: boolean;
|
||||
enableDisplayBasedOnLocale: boolean;
|
||||
}
|
||||
|
||||
export const ADF_AMOUNT_SETTINGS = new InjectionToken<AmountWidgetSettings>('adf-amount-settings');
|
||||
export const ADF_AMOUNT_SETTINGS = new InjectionToken<Observable<AmountWidgetSettings> | AmountWidgetSettings>('adf-amount-settings');
|
||||
|
||||
@Component({
|
||||
selector: 'amount-widget',
|
||||
@@ -49,13 +54,25 @@ export const ADF_AMOUNT_SETTINGS = new InjectionToken<AmountWidgetSettings>('adf
|
||||
'(select)': 'event($event)'
|
||||
},
|
||||
imports: [MatFormFieldModule, MatInputModule, FormsModule, ErrorWidgetComponent, TranslatePipe, NgIf],
|
||||
providers: [CurrencyPipe],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class AmountWidgetComponent extends WidgetComponent implements OnInit {
|
||||
static DEFAULT_CURRENCY: string = '$';
|
||||
private showPlaceholder = true;
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
|
||||
amountWidgetValue: string;
|
||||
currency: string = AmountWidgetComponent.DEFAULT_CURRENCY;
|
||||
currencyDisplay: string | boolean = 'symbol';
|
||||
decimalProperty: string;
|
||||
enableDisplayBasedOnLocale: boolean;
|
||||
isInputInFocus = false;
|
||||
locale: string;
|
||||
notShowDecimalDigits = '1.0-0';
|
||||
showDecimalDigits = '1.2-2';
|
||||
showReadonlyPlaceholder: boolean;
|
||||
valueAsNumber: number;
|
||||
|
||||
get placeholder(): string {
|
||||
return this.showPlaceholder ? this.field.placeholder : '';
|
||||
@@ -63,22 +80,103 @@ export class AmountWidgetComponent extends WidgetComponent implements OnInit {
|
||||
|
||||
constructor(
|
||||
public formService: FormService,
|
||||
@Inject(ADF_AMOUNT_SETTINGS)
|
||||
@Optional()
|
||||
private settings: AmountWidgetSettings
|
||||
@Optional() @Inject(ADF_AMOUNT_SETTINGS) settings: Observable<AmountWidgetSettings> | AmountWidgetSettings,
|
||||
private currencyPipe: CurrencyPipe,
|
||||
private translationService: TranslationService
|
||||
) {
|
||||
super(formService);
|
||||
if (isObservable(settings)) {
|
||||
settings.pipe(takeUntilDestroyed()).subscribe((data: AmountWidgetSettings) => {
|
||||
this.updateSettingsBasedProperties(data);
|
||||
});
|
||||
} else {
|
||||
this.updateSettingsBasedProperties(settings);
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
if (this.field) {
|
||||
if (this.field.currency) {
|
||||
this.currency = this.field.currency;
|
||||
} else {
|
||||
if (this.enableDisplayBasedOnLocale) {
|
||||
this.currency = '';
|
||||
this.currencyDisplay = '';
|
||||
}
|
||||
}
|
||||
|
||||
if (this.field.readOnly) {
|
||||
this.showPlaceholder = this.settings?.showReadonlyPlaceholder;
|
||||
this.showPlaceholder = this.showReadonlyPlaceholder;
|
||||
}
|
||||
this.subscribeToFieldChanges();
|
||||
this.setInitialValues();
|
||||
}
|
||||
}
|
||||
|
||||
amountWidgetOnBlur(): void {
|
||||
this.isInputInFocus = false;
|
||||
if (this.enableDisplayBasedOnLocale) {
|
||||
if (this.amountWidgetValue) {
|
||||
this.valueAsNumber = parseFloat(this.amountWidgetValue);
|
||||
this.amountWidgetValue = this.currencyPipe.transform(
|
||||
this.amountWidgetValue,
|
||||
this.currency,
|
||||
this.currencyDisplay,
|
||||
this.decimalProperty
|
||||
);
|
||||
} else {
|
||||
this.valueAsNumber = null;
|
||||
this.amountWidgetValue = null;
|
||||
}
|
||||
}
|
||||
this.markAsTouched();
|
||||
}
|
||||
|
||||
amountWidgetOnFocus(): void {
|
||||
this.isInputInFocus = true;
|
||||
if (this.enableDisplayBasedOnLocale) {
|
||||
const hasValue = this.valueAsNumber === 0 || this.valueAsNumber;
|
||||
this.amountWidgetValue = hasValue ? this.valueAsNumber.toString() : null;
|
||||
}
|
||||
}
|
||||
|
||||
onFieldChangedAmountWidget(): void {
|
||||
this.field.value = this.amountWidgetValue;
|
||||
super.onFieldChanged(this.field);
|
||||
}
|
||||
|
||||
setInitialValues(): void {
|
||||
if (this.enableDisplayBasedOnLocale) {
|
||||
this.decimalProperty = this.field.enableFractions ? this.showDecimalDigits : this.notShowDecimalDigits;
|
||||
this.locale = this.translationService.getLocale();
|
||||
this.updateValue(this.field.value);
|
||||
} else {
|
||||
this.amountWidgetValue = this.field.value;
|
||||
}
|
||||
}
|
||||
|
||||
subscribeToFieldChanges(): void {
|
||||
this.formService.formFieldValueChanged
|
||||
.pipe(
|
||||
filter((ev: FormFieldEvent) => ev.field.id === this.field.id),
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
)
|
||||
.subscribe((ev: FormFieldEvent) => {
|
||||
if (!this.isInputInFocus && this.enableDisplayBasedOnLocale) {
|
||||
this.updateValue(ev.field.value);
|
||||
} else if (!this.isInputInFocus) {
|
||||
this.amountWidgetValue = ev.field.value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
updateValue(value: any): void {
|
||||
this.valueAsNumber = value;
|
||||
this.amountWidgetValue = this.currencyPipe.transform(value, this.currency, this.currencyDisplay, this.decimalProperty, this.locale);
|
||||
}
|
||||
|
||||
updateSettingsBasedProperties(data: AmountWidgetSettings): void {
|
||||
this.enableDisplayBasedOnLocale = data?.enableDisplayBasedOnLocale ?? false;
|
||||
this.showReadonlyPlaceholder = data?.showReadonlyPlaceholder;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,8 @@ export class TranslationMock implements TranslationService {
|
||||
return of(key);
|
||||
}
|
||||
|
||||
getLocale(): any {}
|
||||
|
||||
instant(key: string | Array<string>): string | any {
|
||||
return key;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,8 @@ export class NoopTranslationService implements TranslationService {
|
||||
return of(key);
|
||||
}
|
||||
|
||||
getLocale(): any {}
|
||||
|
||||
instant(key: string | Array<string>): string | any {
|
||||
return key;
|
||||
}
|
||||
|
||||
@@ -83,4 +83,37 @@ describe('TranslationService', () => {
|
||||
expect(translationService.instant('')).toEqual('');
|
||||
expect(translationService.instant(undefined)).toEqual('');
|
||||
});
|
||||
|
||||
describe('getLocale', () => {
|
||||
it('returns the first language from navigator.languages when available', () => {
|
||||
translationService.userLang = 'it';
|
||||
const returnedLanguages: string[] = ['fr-FR', 'en-US'];
|
||||
const mockLanguages = spyOnProperty(window, 'navigator').and.returnValue({
|
||||
language: 'en-GB',
|
||||
languages: returnedLanguages
|
||||
} as any);
|
||||
|
||||
expect(translationService.getLocale()).toBe('fr-FR');
|
||||
expect(mockLanguages).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('falls back to navigator.language when languages list is absent', () => {
|
||||
translationService.userLang = 'fr';
|
||||
const mockLanguages = spyOnProperty(window, 'navigator').and.returnValue({
|
||||
language: 'de-DE',
|
||||
languages: []
|
||||
} as any);
|
||||
|
||||
expect(translationService.getLocale()).toBe('de-DE');
|
||||
expect(mockLanguages).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('falls back to the provided default locale when navigator is unavailable', () => {
|
||||
translationService.userLang = 'en';
|
||||
const mockLanguages = spyOnProperty(window, 'navigator').and.returnValue(undefined);
|
||||
|
||||
expect(translationService.getLocale()).toBe('en');
|
||||
expect(mockLanguages).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -151,6 +151,22 @@ export class TranslationService {
|
||||
return this.translate.get(key, interpolateParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the preferred locale for the current user.
|
||||
*
|
||||
* @returns Locale identifier resolved from the browser or the default translation locale
|
||||
*/
|
||||
getLocale(): string {
|
||||
const defaultLocale = this.userLang || this.defaultLang;
|
||||
if (typeof window?.navigator === 'undefined') {
|
||||
return defaultLocale;
|
||||
}
|
||||
const wn = window.navigator as Navigator;
|
||||
let lang = wn.languages ? wn.languages[0] : defaultLocale;
|
||||
lang = lang || wn.language;
|
||||
return lang;
|
||||
}
|
||||
|
||||
/**
|
||||
* Directly returns the translation for the supplied key.
|
||||
*
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Inject, Injectable, InjectionToken, Optional } from '@angular/core';
|
||||
import { FormValues, FormModel, FormFieldOption, FormFieldValidator } from '@alfresco/adf-core';
|
||||
import { inject, Inject, Injectable, InjectionToken, Optional } from '@angular/core';
|
||||
import { FormValues, FormModel, FormFieldOption, FormFieldValidator, FormService } from '@alfresco/adf-core';
|
||||
import { Observable, from, EMPTY } from 'rxjs';
|
||||
import { expand, map, reduce, switchMap } from 'rxjs/operators';
|
||||
import { TaskDetailsCloudModel } from '../../task/models/task-details-cloud.model';
|
||||
@@ -35,6 +35,7 @@ export const FORM_CLOUD_SERVICE_FIELD_VALIDATORS_TOKEN = new InjectionToken<Form
|
||||
export class FormCloudService extends BaseCloudService implements FormCloudServiceInterface {
|
||||
private _uploadApi: UploadApi;
|
||||
private fieldValidators: FormFieldValidator[];
|
||||
private formService = inject(FormService);
|
||||
get uploadApi(): UploadApi {
|
||||
this._uploadApi = this._uploadApi ?? new UploadApi(this.apiService.getInstance());
|
||||
return this._uploadApi;
|
||||
@@ -226,7 +227,7 @@ export class FormCloudService extends BaseCloudService implements FormCloudServi
|
||||
formValues[variable.name] = variable.value;
|
||||
});
|
||||
|
||||
return new FormModel(flattenForm, formValues, readOnly, undefined, undefined, this.fieldValidators);
|
||||
return new FormModel(flattenForm, formValues, readOnly, this.formService, undefined, this.fieldValidators);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user