mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[AAE-20769] Fix precision for incoming values in bigdecimal field (#9434)
* [AAE-20769] Fix precision for incoming values in bigdecimal field * CR
This commit is contained in:
@@ -38,7 +38,8 @@ import {
|
|||||||
checkboxWidgetFormVisibilityMock,
|
checkboxWidgetFormVisibilityMock,
|
||||||
dateWidgetFormVisibilityMock,
|
dateWidgetFormVisibilityMock,
|
||||||
multilineWidgetFormVisibilityMock,
|
multilineWidgetFormVisibilityMock,
|
||||||
displayTextWidgetFormVisibilityMock
|
displayTextWidgetFormVisibilityMock,
|
||||||
|
displayBigDecimalWidgetMock
|
||||||
} from './mock/form-renderer.component.mock';
|
} from './mock/form-renderer.component.mock';
|
||||||
import { FormService } from '../services/form.service';
|
import { FormService } from '../services/form.service';
|
||||||
import { CoreTestingModule } from '../../testing';
|
import { CoreTestingModule } from '../../testing';
|
||||||
@@ -849,4 +850,15 @@ describe('Form Renderer Component', () => {
|
|||||||
expectElementToBeHidden(displayTextContainer);
|
expectElementToBeHidden(displayTextContainer);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Display Bigdecimal Widget', () => {
|
||||||
|
it('should round decimal field value to correct precision', async () => {
|
||||||
|
formRendererComponent.formDefinition = formService.parseForm(displayBigDecimalWidgetMock.formRepresentation.formDefinition);
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
|
||||||
|
const decimalInputElement = fixture.nativeElement.querySelector('#Decimal0tzu53');
|
||||||
|
expect(decimalInputElement.value).toBeTruthy('10.12');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@@ -15,11 +15,12 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Component, ViewEncapsulation, Input, OnDestroy, Injector, OnChanges } from '@angular/core';
|
import { Component, ViewEncapsulation, Input, OnDestroy, Injector, OnChanges, OnInit, Inject } from '@angular/core';
|
||||||
import { FormRulesManager, formRulesManagerFactory } from '../models/form-rules.model';
|
import { FormRulesManager, formRulesManagerFactory } from '../models/form-rules.model';
|
||||||
import { FormModel } from './widgets/core/form.model';
|
import { FormModel } from './widgets/core/form.model';
|
||||||
import { ContainerModel, FormFieldModel, TabModel } from './widgets';
|
import { ContainerModel, FormFieldModel, TabModel } from './widgets';
|
||||||
import { FormService } from '../services/form.service';
|
import { FormService } from '../services/form.service';
|
||||||
|
import { FORM_FIELD_MODEL_RENDER_MIDDLEWARE, FormFieldModelRenderMiddleware } from './middlewares/middleware';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'adf-form-renderer',
|
selector: 'adf-form-renderer',
|
||||||
@@ -31,10 +32,11 @@ import { FormService } from '../services/form.service';
|
|||||||
useFactory: formRulesManagerFactory,
|
useFactory: formRulesManagerFactory,
|
||||||
deps: [Injector]
|
deps: [Injector]
|
||||||
}
|
}
|
||||||
|
|
||||||
],
|
],
|
||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class FormRendererComponent<T> implements OnChanges, OnDestroy {
|
export class FormRendererComponent<T> implements OnInit, OnChanges, OnDestroy {
|
||||||
/** Toggle debug options. */
|
/** Toggle debug options. */
|
||||||
@Input()
|
@Input()
|
||||||
showDebugButton: boolean = false;
|
showDebugButton: boolean = false;
|
||||||
@@ -46,7 +48,16 @@ export class FormRendererComponent<T> implements OnChanges, OnDestroy {
|
|||||||
|
|
||||||
fields: FormFieldModel[];
|
fields: FormFieldModel[];
|
||||||
|
|
||||||
constructor(public formService: FormService, private formRulesManager: FormRulesManager<T>) {}
|
constructor(
|
||||||
|
public formService: FormService,
|
||||||
|
private formRulesManager: FormRulesManager<T>,
|
||||||
|
@Inject(FORM_FIELD_MODEL_RENDER_MIDDLEWARE)
|
||||||
|
private middlewareServices: FormFieldModelRenderMiddleware[]
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.runMiddlewareServices();
|
||||||
|
}
|
||||||
|
|
||||||
ngOnChanges(): void {
|
ngOnChanges(): void {
|
||||||
this.formRulesManager.initialize(this.formDefinition);
|
this.formRulesManager.initialize(this.formDefinition);
|
||||||
@@ -123,4 +134,16 @@ export class FormRendererComponent<T> implements OnChanges, OnDestroy {
|
|||||||
const colspan = container ? container.field.colspan : 1;
|
const colspan = container ? container.field.colspan : 1;
|
||||||
return (100 / container.field.numberOfColumns) * colspan + '';
|
return (100 / container.field.numberOfColumns) * colspan + '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private runMiddlewareServices(): void {
|
||||||
|
const formFields = this.formDefinition.getFormFields();
|
||||||
|
|
||||||
|
formFields.forEach(field => {
|
||||||
|
this.middlewareServices.forEach((middlewareService) => {
|
||||||
|
if (middlewareService.type === field.type) {
|
||||||
|
field = middlewareService.getParsedField(field);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,83 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { FormFieldModel, FormFieldTypes, FormModel } from '../widgets';
|
||||||
|
import { DecimalRenderMiddlewareService } from './decimal-middleware.service';
|
||||||
|
|
||||||
|
describe('DecimalRenderMiddlewareService', () => {
|
||||||
|
let decimalMiddlewareService: DecimalRenderMiddlewareService;
|
||||||
|
let formFieldModel: FormFieldModel;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
decimalMiddlewareService = new DecimalRenderMiddlewareService();
|
||||||
|
|
||||||
|
const form = new FormModel();
|
||||||
|
formFieldModel = new FormFieldModel(form, {
|
||||||
|
type: FormFieldTypes.DECIMAL,
|
||||||
|
id: 'id',
|
||||||
|
precision: 3,
|
||||||
|
value: '10.1060'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return field with proper precisison', () => {
|
||||||
|
formFieldModel.value = '10.1000000000000';
|
||||||
|
formFieldModel.precision = 3;
|
||||||
|
const parsedField = decimalMiddlewareService.getParsedField(formFieldModel);
|
||||||
|
expect(parsedField.value).toBe('10.100');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should round up number with correct precisison', () => {
|
||||||
|
formFieldModel.value = '10.1039999';
|
||||||
|
formFieldModel.precision = 3;
|
||||||
|
const parsedField = decimalMiddlewareService.getParsedField(formFieldModel);
|
||||||
|
expect(parsedField.value).toBe('10.104');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should round up number, when removed fraction part starts with number larger or equal 5', () => {
|
||||||
|
formFieldModel.value = '10.1035000';
|
||||||
|
formFieldModel.precision = 3;
|
||||||
|
const parsedField = decimalMiddlewareService.getParsedField(formFieldModel);
|
||||||
|
expect(parsedField.value).toBe('10.104');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should NOT round up number, when removed fraction part starts with number smaller than 5', () => {
|
||||||
|
formFieldModel.value = '10.1034999';
|
||||||
|
formFieldModel.precision = 3;
|
||||||
|
const parsedField = decimalMiddlewareService.getParsedField(formFieldModel);
|
||||||
|
expect(parsedField.value).toBe('10.103');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the same value when precision is correct', () => {
|
||||||
|
formFieldModel.value = '10.123';
|
||||||
|
formFieldModel.precision = 3;
|
||||||
|
const parsedField = decimalMiddlewareService.getParsedField(formFieldModel);
|
||||||
|
expect(parsedField.value).toBe('10.123');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should work when value is not defined', () => {
|
||||||
|
formFieldModel.value = null;
|
||||||
|
const parsedField = decimalMiddlewareService.getParsedField(formFieldModel);
|
||||||
|
expect(parsedField.value).toBe(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should work when value is number', () => {
|
||||||
|
formFieldModel.value = 3.333;
|
||||||
|
const parsedField = decimalMiddlewareService.getParsedField(formFieldModel);
|
||||||
|
expect(parsedField.value).toBe(3.333);
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,53 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { FormFieldModelRenderMiddleware } from './middleware';
|
||||||
|
import { FormFieldModel, FormFieldTypes } from '../widgets';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class DecimalRenderMiddlewareService implements FormFieldModelRenderMiddleware {
|
||||||
|
type = FormFieldTypes.DECIMAL;
|
||||||
|
|
||||||
|
getParsedField(field: FormFieldModel): FormFieldModel {
|
||||||
|
const allowedMaxPrecision = field.precision;
|
||||||
|
const value = field.value;
|
||||||
|
|
||||||
|
field.value = this.forceMaxPrecisionIfNeeded(value, allowedMaxPrecision);
|
||||||
|
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
||||||
|
private forceMaxPrecisionIfNeeded(value: string | number, allowedMaxPrecision): string | number {
|
||||||
|
let numberOfDecimalDigits = 0;
|
||||||
|
const stringValue = typeof value === 'string' ? value : `${value}`;
|
||||||
|
const numberChunks = stringValue.split('.');
|
||||||
|
|
||||||
|
if (numberChunks.length === 2) {
|
||||||
|
numberOfDecimalDigits = numberChunks[1].length;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numberOfDecimalDigits > allowedMaxPrecision) {
|
||||||
|
const valueWithCorrectPrecision = parseFloat(value.toString())
|
||||||
|
.toFixed(allowedMaxPrecision);
|
||||||
|
|
||||||
|
return valueWithCorrectPrecision;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
};
|
26
lib/core/src/lib/form/components/middlewares/middleware.ts
Normal file
26
lib/core/src/lib/form/components/middlewares/middleware.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { InjectionToken } from '@angular/core';
|
||||||
|
import { FormFieldModel } from '../../components/widgets';
|
||||||
|
|
||||||
|
export interface FormFieldModelRenderMiddleware {
|
||||||
|
type: string;
|
||||||
|
getParsedField(field: FormFieldModel): FormFieldModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FORM_FIELD_MODEL_RENDER_MIDDLEWARE = new InjectionToken('RENDER_FORM_FIELD_MODEL_MIDDLEWARE');
|
@@ -15,6 +15,8 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { FormFieldTypes } from '../widgets';
|
||||||
|
|
||||||
export const formDisplayValueVisibility = {
|
export const formDisplayValueVisibility = {
|
||||||
formRepresentation: {
|
formRepresentation: {
|
||||||
id: 'form-3175b074-53c6-4b5b-92df-246b62108db3',
|
id: 'form-3175b074-53c6-4b5b-92df-246b62108db3',
|
||||||
@@ -2086,3 +2088,50 @@ export const displayTextWidgetFormVisibilityMock = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const displayBigDecimalWidgetMock = {
|
||||||
|
formRepresentation: {
|
||||||
|
id: 'form-098756a5-2222-4c3a-1111-81dabc9a88b6',
|
||||||
|
name: 'displayBigdecimalForm',
|
||||||
|
description: '',
|
||||||
|
version: 0,
|
||||||
|
standAlone: true,
|
||||||
|
formDefinition: {
|
||||||
|
tabs: [],
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
id: '45269202-5f2a-438e-b14c-fe13eb4b2aa1',
|
||||||
|
name: 'Label',
|
||||||
|
type: 'container',
|
||||||
|
tab: null,
|
||||||
|
numberOfColumns: 2,
|
||||||
|
fields: {
|
||||||
|
1: [
|
||||||
|
{
|
||||||
|
id: 'Decimal0tzu53',
|
||||||
|
name: 'Bigdecimal',
|
||||||
|
type: FormFieldTypes.DECIMAL,
|
||||||
|
required: false,
|
||||||
|
colspan: 1,
|
||||||
|
placeholder: null,
|
||||||
|
minLength: 0,
|
||||||
|
maxLength: 0,
|
||||||
|
regexPattern: null,
|
||||||
|
visibilityCondition: null,
|
||||||
|
precision: 2,
|
||||||
|
value: '10.12345678',
|
||||||
|
params: {
|
||||||
|
existingColspan: 1,
|
||||||
|
maxColspan: 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
outcomes: [],
|
||||||
|
metadata: {},
|
||||||
|
variables: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@@ -23,7 +23,6 @@
|
|||||||
pattern="-?[0-9]*(\.[0-9]*)?"
|
pattern="-?[0-9]*(\.[0-9]*)?"
|
||||||
[id]="field.id"
|
[id]="field.id"
|
||||||
[required]="isRequired()"
|
[required]="isRequired()"
|
||||||
[value]="displayValue"
|
|
||||||
[(ngModel)]="field.value"
|
[(ngModel)]="field.value"
|
||||||
(ngModelChange)="onFieldChanged(field)"
|
(ngModelChange)="onFieldChanged(field)"
|
||||||
[disabled]="field.readOnly"
|
[disabled]="field.readOnly"
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
|
import { Component, ViewEncapsulation } from '@angular/core';
|
||||||
import { FormService } from '../../../services/form.service';
|
import { FormService } from '../../../services/form.service';
|
||||||
import { WidgetComponent } from '../widget.component';
|
import { WidgetComponent } from '../widget.component';
|
||||||
|
|
||||||
@@ -36,14 +36,8 @@ import { WidgetComponent } from '../widget.component';
|
|||||||
},
|
},
|
||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class DecimalWidgetComponent extends WidgetComponent implements OnInit {
|
export class DecimalWidgetComponent extends WidgetComponent {
|
||||||
displayValue: number;
|
|
||||||
|
|
||||||
constructor(public formService: FormService) {
|
constructor(public formService: FormService) {
|
||||||
super(formService);
|
super(formService);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.displayValue = this.field.value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -37,6 +37,8 @@ import { EditJsonDialogModule } from '../dialogs/edit-json/edit-json.dialog.modu
|
|||||||
import { A11yModule } from '@angular/cdk/a11y';
|
import { A11yModule } from '@angular/cdk/a11y';
|
||||||
import { ViewerModule } from '../viewer/viewer.module';
|
import { ViewerModule } from '../viewer/viewer.module';
|
||||||
import { InplaceFormInputComponent } from './components/inplace-form-input/inplace-form-input.component';
|
import { InplaceFormInputComponent } from './components/inplace-form-input/inplace-form-input.component';
|
||||||
|
import { FORM_FIELD_MODEL_RENDER_MIDDLEWARE } from './components/middlewares/middleware';
|
||||||
|
import { DecimalRenderMiddlewareService } from './components/middlewares/decimal-middleware.service';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -70,7 +72,12 @@ import { InplaceFormInputComponent } from './components/inplace-form-input/inpla
|
|||||||
...WIDGET_DIRECTIVES,
|
...WIDGET_DIRECTIVES,
|
||||||
InplaceFormInputComponent,
|
InplaceFormInputComponent,
|
||||||
WidgetComponent
|
WidgetComponent
|
||||||
]
|
],
|
||||||
|
providers: [{
|
||||||
|
provide: FORM_FIELD_MODEL_RENDER_MIDDLEWARE,
|
||||||
|
useClass: DecimalRenderMiddlewareService,
|
||||||
|
multi: true
|
||||||
|
}]
|
||||||
})
|
})
|
||||||
export class FormBaseModule {
|
export class FormBaseModule {
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user