Skip to content

Commit c20472b

Browse files
authored
Merge pull request #3035 from brampeirs/number-input-validation
feat: enhance increment and decrement functionality number component
2 parents 8852b11 + 9ebc8ae commit c20472b

File tree

3 files changed

+91
-5
lines changed

3 files changed

+91
-5
lines changed

src/number-input/number.component.spec.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,29 @@ describe("Number", () => {
108108
buttonUp.click();
109109
fixture.detectChanges();
110110
expect(component.value).toEqual(2);
111+
});
112+
113+
it("should increment and set value to max if value + step exceeds max", () => {
114+
fixture.detectChanges();
115+
buttonUp = fixture.debugElement.query(By.css(".up-icon")).nativeElement;
116+
component.value = 95;
117+
component.step = 10;
118+
component.max = 100;
119+
buttonUp.click();
120+
fixture.detectChanges();
121+
expect(component.value).toEqual(100);
122+
});
123+
124+
it("should increment and set value to min if value + step is less than min", () => {
125+
fixture.detectChanges();
126+
buttonUp = fixture.debugElement.query(By.css(".up-icon")).nativeElement;
127+
component.value = 0;
128+
component.step = 2;
129+
component.min = 5;
130+
buttonUp.click();
131+
fixture.detectChanges();
132+
133+
expect(component.value).toBe(5);
111134
});
112135

113136
it("should not increment value if max is reached", () => {
@@ -129,6 +152,29 @@ describe("Number", () => {
129152
expect(component.value).toEqual(0);
130153
});
131154

155+
it("should decrement and set value to max if value - step exceeds max", () => {
156+
fixture.detectChanges();
157+
buttonUp = fixture.debugElement.query(By.css(".down-icon")).nativeElement;
158+
component.value = 20;
159+
component.step = 2;
160+
component.max = 15;
161+
buttonUp.click();
162+
fixture.detectChanges();
163+
164+
expect(component.value).toBe(15);
165+
});
166+
167+
it("should decrement and set value to min if value - step is less than min", () => {
168+
fixture.detectChanges();
169+
buttonUp = fixture.debugElement.query(By.css(".down-icon")).nativeElement;
170+
component.value = 6;
171+
component.step = 2;
172+
component.min = 5;
173+
buttonUp.click();
174+
fixture.detectChanges();
175+
expect(component.value).toEqual(5);
176+
});
177+
132178
it("should not decrement value min is reached", () => {
133179
fixture.detectChanges();
134180
buttonUp = fixture.debugElement.query(By.css(".down-icon")).nativeElement;

src/number-input/number.component.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,23 @@ export class NumberComponent implements ControlValueAccessor {
352352
* Adds `step` to the current `value`.
353353
*/
354354
onIncrement(): void {
355+
// if max is set and value + step is greater than max, set value to max
356+
// example: max = 100, step = 10, value = 95 , value + step = 105, value will be set to 100 (max) instead of 105
357+
if (this.max !== null && this.value + this.step > this.max) {
358+
this.value = this.max;
359+
this.emitChangeEvent();
360+
return;
361+
}
362+
363+
// if min is set and value + step is less than min, set value to min
364+
// example: min = 5, step = 2, value = 0, value + step = 2, value will be set to 5 (min) instead of 2
365+
if (this.min !== null && this.value + this.step < this.min) {
366+
this.value = this.min;
367+
this.emitChangeEvent();
368+
return;
369+
}
370+
371+
// if max is not set or value + step is less than max, increment value by step
355372
if (this.max === null || this.value + this.step <= this.max) {
356373
this.value += this.step;
357374
this.value = parseFloat(this.value.toPrecision(this.precision));
@@ -363,6 +380,23 @@ export class NumberComponent implements ControlValueAccessor {
363380
* Subtracts `step` to the current `value`.
364381
*/
365382
onDecrement(): void {
383+
// if max is set and value - step is greater than max, set value to max
384+
// example: max = 15, step = 2, value = 20, value - step = 18, value will be set to 15 (max) instead of 18
385+
if (this.max !== null && this.value - this.step > this.max) {
386+
this.value = this.max;
387+
this.emitChangeEvent();
388+
return;
389+
}
390+
391+
// if min is set and value - step is less than min, set value to min
392+
// example: min = 5, step = 2, value = 6, value - step = 4, value will be set to 5 (min) instead of 4
393+
if (this.min !== null && this.value - this.step < this.min) {
394+
this.value = this.min;
395+
this.emitChangeEvent();
396+
return;
397+
}
398+
399+
// if min is not set or value - step is greater than min, decrement value by step
366400
if (this.min === null || this.value - this.step >= this.min) {
367401
this.value -= this.step;
368402
this.value = parseFloat(this.value.toPrecision(this.precision));

src/number-input/number.stories.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
/* tslint:disable variable-name */
22

33
import { moduleMetadata, Meta } from "@storybook/angular";
4+
import { FormsModule } from "@angular/forms";
45
import { NumberModule, NumberComponent } from "./";
56

67
export default {
78
title: "Components/Number Input",
89
decorators: [
910
moduleMetadata({
10-
imports: [NumberModule]
11+
imports: [NumberModule, FormsModule]
1112
})
1213
],
1314
args: {
@@ -35,7 +36,9 @@ export default {
3536
theme: {
3637
options: ["light", "dark"],
3738
control: "radio"
38-
}
39+
},
40+
// Actions
41+
change: { action: 'changed'}
3942
},
4043
component: NumberComponent
4144
} as Meta;
@@ -57,7 +60,8 @@ const Template = (args) => ({
5760
[size]="size"
5861
[readonly]="readonly"
5962
[disabled]="disabled"
60-
[fluid]="fluid">
63+
[fluid]="fluid"
64+
(change)="change($event)">
6165
</cds-number>
6266
`
6367
});
@@ -86,7 +90,8 @@ const ModelTemplate = (args) => ({
8690
[warnText]="warnText"
8791
[disabled]="disabled"
8892
[(ngModel)]="value"
89-
[fluid]="fluid">
93+
[fluid]="fluid"
94+
(change)="change($event)">
9095
</cds-number>
9196
{{ value }}
9297
`
@@ -100,7 +105,8 @@ const SkeletonTemplate = (args) => ({
100105
<cds-number
101106
label="Number input label"
102107
skeleton="true"
103-
[fluid]="fluid">
108+
[fluid]="fluid"
109+
(change)="change($event)">
104110
</cds-number>
105111
`
106112
});

0 commit comments

Comments
 (0)