mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-05-26 17:24:56 +00:00
Create a new widget for decimal type (#9335)
* [AAE-19481] Create a new widget for decimal type * update * CR * unit for decimal widgets * added test for positibe validator * added decimal validator tests * cr
This commit is contained in:
parent
300d46dc7e
commit
16005ef298
@ -91,10 +91,9 @@ export class CardViewItemDispatcherComponent implements OnChanges {
|
||||
this.loaded = true;
|
||||
}
|
||||
|
||||
Object.keys(changes)
|
||||
.map((changeName) => [changeName, changes[changeName]])
|
||||
.forEach(([inputParamName, simpleChange]: [string, SimpleChange]) => {
|
||||
this.componentReference.instance[inputParamName] = simpleChange.currentValue;
|
||||
Object.entries(changes)
|
||||
.forEach(([changeName, change]: [string, SimpleChange]) => {
|
||||
this.componentReference.instance[changeName] = change.currentValue;
|
||||
});
|
||||
|
||||
this.proxy('ngOnChanges', changes);
|
||||
|
@ -24,3 +24,11 @@ export interface CardViewTextItemProperties extends CardViewItemProperties {
|
||||
pipes?: CardViewTextItemPipeProperty[];
|
||||
clickCallBack?: any;
|
||||
}
|
||||
|
||||
export interface CardViewIntItemProperties extends CardViewTextItemProperties {
|
||||
allowOnlyPositiveNumbers?: boolean;
|
||||
}
|
||||
|
||||
export interface CardViewFloatItemProperties extends CardViewTextItemProperties {
|
||||
precision?: number;
|
||||
}
|
||||
|
@ -48,7 +48,8 @@ export abstract class CardViewBaseItemModel<T = any> {
|
||||
if (props?.constraints?.length ?? 0) {
|
||||
for (const constraint of props.constraints) {
|
||||
if (constraint.type !== 'LIST') {
|
||||
this.validators.push(validatorsMap[constraint.type.toLowerCase()](constraint.parameters));
|
||||
const validatorFactory = validatorsMap[constraint.type.toLowerCase()];
|
||||
this.validators.push(validatorFactory(constraint.parameters));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ export class CardViewFloatItemModel extends CardViewTextItemModel implements Car
|
||||
super(cardViewTextItemProperties);
|
||||
|
||||
this.validators.push(new CardViewItemFloatValidator());
|
||||
|
||||
if (cardViewTextItemProperties.value && !cardViewTextItemProperties.multivalued) {
|
||||
this.value = parseFloat(cardViewTextItemProperties.value);
|
||||
}
|
||||
|
@ -18,19 +18,24 @@
|
||||
import { CardViewItem } from '../interfaces/card-view-item.interface';
|
||||
import { DynamicComponentModel } from '../../common/services/dynamic-component-mapper.service';
|
||||
import { CardViewTextItemModel } from './card-view-textitem.model';
|
||||
import { CardViewTextItemProperties } from '../interfaces/card-view.interfaces';
|
||||
import { CardViewItemIntValidator } from '../validators/card-view.validators';
|
||||
import { CardViewIntItemProperties } from '../interfaces/card-view.interfaces';
|
||||
import { CardViewItemIntValidator, CardViewItemPositiveIntValidator } from '../validators/card-view.validators';
|
||||
|
||||
export class CardViewIntItemModel extends CardViewTextItemModel implements CardViewItem, DynamicComponentModel {
|
||||
type: string = 'int';
|
||||
inputType: string = 'number';
|
||||
|
||||
constructor(cardViewTextItemProperties: CardViewTextItemProperties) {
|
||||
super(cardViewTextItemProperties);
|
||||
constructor(cardViewIntItemProperties: CardViewIntItemProperties) {
|
||||
super(cardViewIntItemProperties);
|
||||
|
||||
this.validators.push(new CardViewItemIntValidator());
|
||||
if (cardViewTextItemProperties.value && !cardViewTextItemProperties.multivalued) {
|
||||
this.value = parseInt(cardViewTextItemProperties.value, 10);
|
||||
|
||||
if (cardViewIntItemProperties.allowOnlyPositiveNumbers) {
|
||||
this.validators.push(new CardViewItemPositiveIntValidator());
|
||||
}
|
||||
|
||||
if (cardViewIntItemProperties.value && !cardViewIntItemProperties.multivalued) {
|
||||
this.value = parseInt(cardViewIntItemProperties.value, 10);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,50 @@
|
||||
/*!
|
||||
* @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 { CardViewItemPositiveIntValidator } from './card-view-item-only-positive-int.validator';
|
||||
|
||||
describe('CardViewItemPositiveIntValidator', () => {
|
||||
let validator: CardViewItemPositiveIntValidator;
|
||||
|
||||
beforeEach(() => {
|
||||
validator = new CardViewItemPositiveIntValidator();
|
||||
});
|
||||
|
||||
it('should return false for invalid integer value', () => {
|
||||
expect(validator.isValid('a')).toBeFalse();
|
||||
});
|
||||
|
||||
it('should return false for negative value', () => {
|
||||
expect(validator.isValid(-1)).toBeFalse();
|
||||
});
|
||||
|
||||
it('should return true for positive value', () => {
|
||||
expect(validator.isValid(1)).toBeTrue();
|
||||
});
|
||||
|
||||
it('should return true for empty value', () => {
|
||||
expect(validator.isValid('')).toBeTrue();
|
||||
});
|
||||
|
||||
it('should work for negative string value', () => {
|
||||
expect(validator.isValid('-1')).toBeFalse();
|
||||
});
|
||||
|
||||
it('should work for positive string value', () => {
|
||||
expect(validator.isValid('1')).toBeTrue();
|
||||
});
|
||||
});
|
@ -0,0 +1,40 @@
|
||||
/*!
|
||||
* @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 { CardViewItemValidator } from '../interfaces/card-view.interfaces';
|
||||
|
||||
export class CardViewItemPositiveIntValidator implements CardViewItemValidator {
|
||||
message = 'CORE.CARDVIEW.VALIDATORS.ONLY_POSITIVE_NUMBER';
|
||||
|
||||
isValid(value: any | any[]): boolean {
|
||||
if (Array.isArray(value)) {
|
||||
return value.every(this.isPositiveNumber);
|
||||
}
|
||||
|
||||
const valueIsNotSet = value === '';
|
||||
|
||||
return valueIsNotSet ||
|
||||
(
|
||||
!isNaN(value) &&
|
||||
this.isPositiveNumber(value)
|
||||
);
|
||||
}
|
||||
|
||||
private isPositiveNumber(value: any): boolean {
|
||||
return parseInt(value, 10) >= 0;
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
export * from './card-view-item-int.validator';
|
||||
export * from './card-view-item-only-positive-int.validator';
|
||||
export * from './card-view-item-float.validator';
|
||||
export * from './card-view-item-match.valiator';
|
||||
export * from './card-view-item-minmax.valiator';
|
||||
|
@ -24,6 +24,7 @@ export class FormFieldTypes {
|
||||
static TEXT: string = 'text';
|
||||
static STRING: string = 'string';
|
||||
static INTEGER: string = 'integer';
|
||||
static DECIMAL: string = 'bigdecimal';
|
||||
static MULTILINE_TEXT: string = 'multi-line-text';
|
||||
static DROPDOWN: string = 'dropdown';
|
||||
static HYPERLINK: string = 'hyperlink';
|
||||
|
@ -31,7 +31,8 @@ import {
|
||||
MinDateTimeFieldValidator,
|
||||
MaxDateFieldValidator,
|
||||
MinDateFieldValidator,
|
||||
DateTimeFieldValidator
|
||||
DateTimeFieldValidator,
|
||||
DecimalFieldValidator
|
||||
} from './form-field-validator';
|
||||
import { FormFieldModel } from './form-field.model';
|
||||
import { FormModel } from './form.model';
|
||||
@ -1117,4 +1118,73 @@ describe('FormFieldValidator', () => {
|
||||
expect(validator.validate(field)).toBeFalse();
|
||||
});
|
||||
});
|
||||
|
||||
describe('DecimalFieldValidator', () => {
|
||||
let decimalValidator: DecimalFieldValidator;
|
||||
|
||||
beforeEach(() => {
|
||||
decimalValidator = new DecimalFieldValidator();
|
||||
});
|
||||
|
||||
it('should validate decimal with correct precision', () => {
|
||||
const field = new FormFieldModel(new FormModel(), {
|
||||
type: FormFieldTypes.DECIMAL,
|
||||
value: 1.22,
|
||||
precision: 2
|
||||
});
|
||||
|
||||
expect(decimalValidator.validate(field)).toBeTrue();
|
||||
});
|
||||
|
||||
it('should return true when value is of lower precision', () => {
|
||||
const field = new FormFieldModel(new FormModel(), {
|
||||
type: FormFieldTypes.DECIMAL,
|
||||
value: 1.2,
|
||||
precision: 2
|
||||
});
|
||||
|
||||
expect(decimalValidator.validate(field)).toBeTrue();
|
||||
});
|
||||
|
||||
it('should return false when value is of higher precision', () => {
|
||||
const field = new FormFieldModel(new FormModel(), {
|
||||
type: FormFieldTypes.DECIMAL,
|
||||
value: 1.22,
|
||||
precision: 1
|
||||
});
|
||||
|
||||
expect(decimalValidator.validate(field)).toBeFalse();
|
||||
});
|
||||
|
||||
it('should validate decimal of wrong precision when value is of type string', () => {
|
||||
const field = new FormFieldModel(new FormModel(), {
|
||||
type: FormFieldTypes.DECIMAL,
|
||||
value: '1.22',
|
||||
precision: 1
|
||||
});
|
||||
|
||||
expect(decimalValidator.validate(field)).toBeFalse();
|
||||
});
|
||||
|
||||
it('should return false, when value is a negative number and of correct precission', () => {
|
||||
const field = new FormFieldModel(new FormModel(), {
|
||||
type: FormFieldTypes.DECIMAL,
|
||||
value: -1.22,
|
||||
precision: 1
|
||||
});
|
||||
|
||||
expect(decimalValidator.validate(field)).toBeFalse();
|
||||
});
|
||||
|
||||
it('should return true, when value is a positive number and of correct precission', () => {
|
||||
const field = new FormFieldModel(new FormModel(), {
|
||||
type: FormFieldTypes.DECIMAL,
|
||||
value: -1.22,
|
||||
precision: 3
|
||||
});
|
||||
|
||||
expect(decimalValidator.validate(field)).toBeTrue();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
@ -48,7 +48,8 @@ export class RequiredFieldValidator implements FormFieldValidator {
|
||||
FormFieldTypes.DYNAMIC_TABLE,
|
||||
FormFieldTypes.DATE,
|
||||
FormFieldTypes.DATETIME,
|
||||
FormFieldTypes.ATTACH_FOLDER
|
||||
FormFieldTypes.ATTACH_FOLDER,
|
||||
FormFieldTypes.DECIMAL
|
||||
];
|
||||
|
||||
isSupported(field: FormFieldModel): boolean {
|
||||
@ -431,6 +432,7 @@ export class MinValueFieldValidator implements FormFieldValidator {
|
||||
|
||||
private supportedTypes = [
|
||||
FormFieldTypes.NUMBER,
|
||||
FormFieldTypes.DECIMAL,
|
||||
FormFieldTypes.AMOUNT
|
||||
];
|
||||
|
||||
@ -461,6 +463,7 @@ export class MaxValueFieldValidator implements FormFieldValidator {
|
||||
|
||||
private supportedTypes = [
|
||||
FormFieldTypes.NUMBER,
|
||||
FormFieldTypes.DECIMAL,
|
||||
FormFieldTypes.AMOUNT
|
||||
];
|
||||
|
||||
@ -553,6 +556,50 @@ export class FixedValueFieldValidator implements FormFieldValidator {
|
||||
}
|
||||
}
|
||||
|
||||
export class DecimalFieldValidator implements FormFieldValidator {
|
||||
|
||||
private supportedTypes = [
|
||||
FormFieldTypes.DECIMAL
|
||||
];
|
||||
|
||||
isSupported(field: FormFieldModel): boolean {
|
||||
return field && this.supportedTypes.indexOf(field.type) > -1 && !!field.value;
|
||||
}
|
||||
|
||||
validate(field: FormFieldModel): boolean {
|
||||
const shouldValidateField = this.isSupported(field) && field.isVisible;
|
||||
|
||||
if (!shouldValidateField) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const precision = field.precision;
|
||||
const fieldValue = field.value;
|
||||
|
||||
if (!isNumberValue(fieldValue)) {
|
||||
field.validationSummary.message = 'FORM.FIELD.VALIDATOR.INVALID_DECIMAL_NUMBER';
|
||||
return false;
|
||||
}
|
||||
|
||||
const value = typeof fieldValue === 'string' ? fieldValue : fieldValue.toString();
|
||||
const valueParts = value.split('.');
|
||||
const decimalPart = valueParts[1];
|
||||
|
||||
if (decimalPart === undefined) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (decimalPart.length > precision) {
|
||||
field.validationSummary.message = 'FORM.FIELD.VALIDATOR.INVALID_DECIMAL_PRECISION';
|
||||
field.validationSummary.attributes.set('precision', precision.toString());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export const FORM_FIELD_VALIDATORS = [
|
||||
new RequiredFieldValidator(),
|
||||
new NumberFieldValidator(),
|
||||
@ -567,5 +614,6 @@ export const FORM_FIELD_VALIDATORS = [
|
||||
new MaxDateFieldValidator(),
|
||||
new FixedValueFieldValidator(),
|
||||
new MinDateTimeFieldValidator(),
|
||||
new MaxDateTimeFieldValidator()
|
||||
new MaxDateTimeFieldValidator(),
|
||||
new DecimalFieldValidator()
|
||||
];
|
||||
|
@ -58,6 +58,7 @@ export class FormFieldModel extends FormWidgetModel {
|
||||
maxValue: string;
|
||||
maxDateRangeValue: number = 0;
|
||||
minDateRangeValue: number = 0;
|
||||
precision: number;
|
||||
dynamicDateRangeSelection: boolean;
|
||||
regexPattern: string;
|
||||
options: FormFieldOption[] = [];
|
||||
@ -100,9 +101,11 @@ export class FormFieldModel extends FormWidgetModel {
|
||||
}
|
||||
|
||||
set value(v: any) {
|
||||
if (v !== this._value) {
|
||||
this._value = v;
|
||||
this.updateForm();
|
||||
}
|
||||
}
|
||||
|
||||
get readOnly(): boolean {
|
||||
if (this.form?.readOnly) {
|
||||
@ -200,6 +203,7 @@ export class FormFieldModel extends FormWidgetModel {
|
||||
this.groupsRestriction = json.groupsRestriction?.groups;
|
||||
this.variableConfig = json.variableConfig;
|
||||
this.schemaDefinition = json.schemaDefinition;
|
||||
this.precision = json.precision;
|
||||
|
||||
if (json.placeholder && json.placeholder !== '' && json.placeholder !== 'null') {
|
||||
this.placeholder = json.placeholder;
|
||||
@ -459,6 +463,10 @@ export class FormFieldModel extends FormWidgetModel {
|
||||
this.form.values[this.id] = this.enableFractions ? parseFloat(this.value) : parseInt(this.value, 10);
|
||||
break;
|
||||
}
|
||||
case FormFieldTypes.DECIMAL: {
|
||||
this.form.values[this.id] = parseFloat(this.value);
|
||||
break;
|
||||
};
|
||||
case FormFieldTypes.BOOLEAN: {
|
||||
this.form.values[this.id] = this.value !== null && this.value !== undefined ? this.value : false;
|
||||
break;
|
||||
|
@ -0,0 +1,44 @@
|
||||
<div
|
||||
class="adf-textfield adf-decimal-widget {{ field.className }}"
|
||||
[class.adf-invalid]="!field.isValid && isTouched()"
|
||||
[class.adf-readonly]="field.readOnly"
|
||||
[class.adf-left-label-input-container]="field.leftLabels"
|
||||
>
|
||||
<div *ngIf="field.leftLabels">
|
||||
<label class="adf-label adf-left-label" [attr.for]="field.id">
|
||||
{{ field.name | translate }}<span class="adf-asterisk" *ngIf="isRequired()">*</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<mat-form-field [hideRequiredMarker]="true">
|
||||
<label class="adf-label" *ngIf="!field.leftLabels" [attr.for]="field.id">
|
||||
{{ field.name | translate }}<span class="adf-asterisk" *ngIf="isRequired()">*</span>
|
||||
</label>
|
||||
|
||||
<input
|
||||
matInput
|
||||
class="adf-input"
|
||||
type="text"
|
||||
pattern="-?[0-9]*(\.[0-9]*)?"
|
||||
[id]="field.id"
|
||||
[required]="isRequired()"
|
||||
[value]="displayValue"
|
||||
[(ngModel)]="field.value"
|
||||
(ngModelChange)="onFieldChanged(field)"
|
||||
[disabled]="field.readOnly"
|
||||
[placeholder]="field.placeholder"
|
||||
[matTooltip]="field.tooltip"
|
||||
(blur)="markAsTouched()"
|
||||
matTooltipPosition="above"
|
||||
matTooltipShowDelay="1000"
|
||||
/>
|
||||
</mat-form-field>
|
||||
|
||||
<error-widget [error]="field.validationSummary"></error-widget>
|
||||
<error-widget
|
||||
*ngIf="isInvalidFieldRequired() && isTouched()"
|
||||
required="{{ 'FORM.FIELD.REQUIRED' | translate }}">
|
||||
</error-widget>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,9 @@
|
||||
.adf {
|
||||
&-decimal-widget {
|
||||
width: 100%;
|
||||
|
||||
.adf-label {
|
||||
top: 20px;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,175 @@
|
||||
/*!
|
||||
* @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 { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||
import { HarnessLoader } from '@angular/cdk/testing';
|
||||
|
||||
import { DecimalWidgetComponent } from './decimal.component';
|
||||
import { FormService } from '../../../services/form.service';
|
||||
import { FormFieldModel, FormFieldTypes, FormModel } from '../core';
|
||||
import { MatInputHarness } from '@angular/material/input/testing';
|
||||
import { MatTooltipHarness } from '@angular/material/tooltip/testing';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CoreTestingModule } from '../../../../testing';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
describe('DecimalComponent', () => {
|
||||
let loader: HarnessLoader;
|
||||
let widget: DecimalWidgetComponent;
|
||||
let fixture: ComponentFixture<DecimalWidgetComponent>;
|
||||
let element: HTMLElement;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
CoreTestingModule,
|
||||
MatInputModule,
|
||||
FormsModule
|
||||
],
|
||||
declarations: [DecimalWidgetComponent],
|
||||
providers: [FormService]
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(DecimalWidgetComponent);
|
||||
widget = fixture.componentInstance;
|
||||
element = fixture.nativeElement;
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
});
|
||||
|
||||
describe('when tooltip is set', () => {
|
||||
beforeEach(() => {
|
||||
widget.field = new FormFieldModel(new FormModel({ taskId: '<id>' }), {
|
||||
type: FormFieldTypes.DECIMAL,
|
||||
tooltip: 'my custom tooltip'
|
||||
});
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should show tooltip', async () => {
|
||||
const input = await loader.getHarness(MatInputHarness);
|
||||
await (await input.host()).hover();
|
||||
|
||||
const tooltip = await loader.getHarness(MatTooltipHarness);
|
||||
expect(await tooltip.getTooltipText()).toBe('my custom tooltip');
|
||||
});
|
||||
|
||||
it('should hide tooltip', async () => {
|
||||
const input = await loader.getHarness(MatInputHarness);
|
||||
await (await input.host()).hover();
|
||||
await (await input.host()).mouseAway();
|
||||
|
||||
const tooltip = await loader.getHarness(MatTooltipHarness);
|
||||
expect(await tooltip.isOpen()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when is required', () => {
|
||||
beforeEach(() => {
|
||||
widget.field = new FormFieldModel(new FormModel({ taskId: '<id>' }), {
|
||||
type: FormFieldTypes.DECIMAL,
|
||||
required: true
|
||||
});
|
||||
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should be marked as invalid after interaction', async () => {
|
||||
const input = await loader.getHarness(MatInputHarness);
|
||||
expect(fixture.nativeElement.querySelector('.adf-invalid')).toBeFalsy();
|
||||
|
||||
const inputHost = await input.host();
|
||||
await inputHost.blur();
|
||||
fixture.detectChanges();
|
||||
|
||||
const invalidElement = fixture.nativeElement.querySelector('.adf-invalid');
|
||||
|
||||
expect(invalidElement).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should be able to display label with asterisk', async () => {
|
||||
const asterisk = element.querySelector('.adf-asterisk');
|
||||
|
||||
expect(asterisk).toBeTruthy();
|
||||
expect(asterisk?.textContent).toEqual('*');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when form model has left labels', () => {
|
||||
it('should have left labels classes on leftLabels true', async () => {
|
||||
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', leftLabels: true }), {
|
||||
id: 'decimal-id',
|
||||
name: 'decimal-name',
|
||||
value: '',
|
||||
type: FormFieldTypes.DECIMAL,
|
||||
readOnly: false,
|
||||
required: true
|
||||
});
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
const widgetContainer = element.querySelector('.adf-left-label-input-container');
|
||||
expect(widgetContainer).not.toBeNull();
|
||||
|
||||
const adfLeftLabel = element.querySelector('.adf-left-label');
|
||||
expect(adfLeftLabel).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should not have left labels classes on leftLabels false', async () => {
|
||||
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', leftLabels: false }), {
|
||||
id: 'decimal-id',
|
||||
name: 'decimal-name',
|
||||
value: '',
|
||||
type: FormFieldTypes.DECIMAL,
|
||||
readOnly: false,
|
||||
required: true
|
||||
});
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
const widgetContainer = element.querySelector('.adf-left-label-input-container');
|
||||
expect(widgetContainer).toBeNull();
|
||||
|
||||
const adfLeftLabel = element.querySelector('.adf-left-label');
|
||||
expect(adfLeftLabel).toBeNull();
|
||||
});
|
||||
|
||||
it('should not have left labels classes on leftLabels not present', async () => {
|
||||
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), {
|
||||
id: 'decimal-id',
|
||||
name: 'decimal-name',
|
||||
value: '',
|
||||
type: FormFieldTypes.DECIMAL,
|
||||
readOnly: false,
|
||||
required: true
|
||||
});
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
const widgetContainer = element.querySelector('.adf-left-label-input-container');
|
||||
expect(widgetContainer).toBeNull();
|
||||
|
||||
const adfLeftLabel = element.querySelector('.adf-left-label');
|
||||
expect(adfLeftLabel).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
@ -0,0 +1,49 @@
|
||||
/*!
|
||||
* @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 { Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { FormService } from '../../../services/form.service';
|
||||
import { WidgetComponent } from '../widget.component';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-decimal',
|
||||
templateUrl: './decimal.component.html',
|
||||
styleUrls: ['./decimal.component.scss'],
|
||||
host: {
|
||||
'(click)': 'event($event)',
|
||||
'(blur)': 'event($event)',
|
||||
'(change)': 'event($event)',
|
||||
'(focus)': 'event($event)',
|
||||
'(focusin)': 'event($event)',
|
||||
'(focusout)': 'event($event)',
|
||||
'(input)': 'event($event)',
|
||||
'(invalid)': 'event($event)',
|
||||
'(select)': 'event($event)'
|
||||
},
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class DecimalWidgetComponent extends WidgetComponent implements OnInit {
|
||||
displayValue: number;
|
||||
|
||||
constructor(public formService: FormService) {
|
||||
super(formService);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.displayValue = this.field.value;
|
||||
}
|
||||
}
|
@ -30,6 +30,7 @@ import { TextWidgetComponent } from './text/text.widget';
|
||||
import { DateTimeWidgetComponent } from './date-time/date-time.widget';
|
||||
import { JsonWidgetComponent } from './json/json.widget';
|
||||
import { BaseViewerWidgetComponent } from './base-viewer/base-viewer.widget';
|
||||
import { DecimalWidgetComponent } from './decimal/decimal.component';
|
||||
|
||||
// core
|
||||
export * from './widget.component';
|
||||
@ -39,6 +40,7 @@ export * from './core';
|
||||
export * from './unknown/unknown.widget';
|
||||
export * from './text/text.widget';
|
||||
export * from './number/number.widget';
|
||||
export * from './decimal/decimal.component';
|
||||
export * from './checkbox/checkbox.widget';
|
||||
export * from './multiline-text/multiline-text.widget';
|
||||
export * from './hyperlink/hyperlink.widget';
|
||||
@ -55,6 +57,7 @@ export const WIDGET_DIRECTIVES: any[] = [
|
||||
UnknownWidgetComponent,
|
||||
TextWidgetComponent,
|
||||
NumberWidgetComponent,
|
||||
DecimalWidgetComponent,
|
||||
CheckboxWidgetComponent,
|
||||
MultilineTextWidgetComponentComponent,
|
||||
HyperlinkWidgetComponent,
|
||||
|
@ -35,6 +35,7 @@ export class FormRenderingService extends DynamicComponentMapper {
|
||||
[FormFieldTypes.TEXT]: DynamicComponentResolver.fromType(widgets.TextWidgetComponent),
|
||||
[FormFieldTypes.STRING]: DynamicComponentResolver.fromType(widgets.TextWidgetComponent),
|
||||
[FormFieldTypes.INTEGER]: DynamicComponentResolver.fromType(widgets.NumberWidgetComponent),
|
||||
[FormFieldTypes.DECIMAL]: DynamicComponentResolver.fromType(widgets.DecimalWidgetComponent),
|
||||
[FormFieldTypes.MULTILINE_TEXT]: DynamicComponentResolver.fromType(widgets.MultilineTextWidgetComponentComponent),
|
||||
[FormFieldTypes.BOOLEAN]: DynamicComponentResolver.fromType(widgets.CheckboxWidgetComponent),
|
||||
[FormFieldTypes.DATE]: DynamicComponentResolver.fromType(widgets.DateWidgetComponent),
|
||||
|
@ -52,6 +52,8 @@
|
||||
"NO_FILE_ATTACHED": "No file attached",
|
||||
"VALIDATOR": {
|
||||
"INVALID_NUMBER": "Use a different number format",
|
||||
"INVALID_DECIMAL_NUMBER": "Use a decimal number format",
|
||||
"INVALID_DECIMAL_PRECISION": "Incorrect decimal value, there should be a maximum of {{precision}} digits after the decimal point.",
|
||||
"INVALID_DATE": "Use a different date format",
|
||||
"INVALID_VALUE": "Enter a different value",
|
||||
"NOT_GREATER_THAN": "Can't be greater than {{ maxValue }}",
|
||||
@ -192,7 +194,8 @@
|
||||
"INT_VALIDATION_ERROR": "Use an integer format",
|
||||
"LENGTH_VALIDATION_ERROR": "Value should be between {{ minLength }} and {{ maxLength }} in length",
|
||||
"MATCH_VALIDATION_ERROR": "Value doesn't match pattern: {{ expression }}",
|
||||
"MINMAX_VALIDATION_ERROR": "Value should be between {{ minValue }} and {{ maxValue }}"
|
||||
"MINMAX_VALIDATION_ERROR": "Value should be between {{ minValue }} and {{ maxValue }}",
|
||||
"ONLY_POSITIVE_NUMBER": "Only positive value is allowed"
|
||||
},
|
||||
"MORE": "More"
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user