Skip to content

Commit

Permalink
fix(module: stepper): fix stepper js float calculation bug (#280)
Browse files Browse the repository at this point in the history
  • Loading branch information
sWhite01111 authored and fisherspy committed Feb 19, 2019
1 parent acb180e commit 5cd1f6c
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 50 deletions.
70 changes: 34 additions & 36 deletions components/stepper/stepper.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,31 +89,25 @@ describe('StepperComponent', () => {
expect(component.defaultValue).toBe(11, 'value == defaultValue');
});
it('should step work', () => {
component.value = 5;
component.value = 1e-13;
component.step = 2;
fixture.detectChanges();
downButton.click();
expect(component.value).toBe(3, 'step is 2');
expect(component.value).toBe(-1.9999999999999, 'step is 2');
component.step = 3;
fixture.detectChanges();
upButton.click();
expect(component.value).toBe(6, 'step is 3');
expect(component.value).toBe(1.0000000000001, 'step is 3');
});

it('should showNumber work', () => {
expect(stepperEle.nativeElement.classList).toContain('showNumber', 'showNumber');
component.showNumber = false;
fixture.detectChanges();
expect(stepperEle.nativeElement.classList).not.toContain(
'showNumber',
'showNumber is not show'
);
expect(stepperEle.nativeElement.classList).not.toContain('showNumber', 'showNumber is not show');
});
it('should disabled work', () => {
expect(stepperEle.nativeElement.classList).not.toContain(
'am-stepper-disabled',
'not contain am-stepper-disabled'
);
expect(stepperEle.nativeElement.classList).not.toContain('am-stepper-disabled', 'not contain am-stepper-disabled');
component.disabled = true;
component.value = 5;
fixture.detectChanges();
Expand All @@ -133,10 +127,7 @@ describe('StepperComponent', () => {
upButton.click();
expect(component.value).toBe(5, 'click down button');

expect(stepperEle.nativeElement.classList).toContain(
'am-stepper-disabled',
'contain am-stepper-disabled'
);
expect(stepperEle.nativeElement.classList).toContain('am-stepper-disabled', 'contain am-stepper-disabled');
});

it('should readOnly work', fakeAsync(() => {
Expand Down Expand Up @@ -174,6 +165,9 @@ describe('StepperComponent', () => {
});

it('should ngModel work', () => {
component.modelValue = 4;
fixture.detectChanges();

const downEl = stepperEles[1].nativeElement.querySelector('.am-stepper-handler-down');
component.modelChange = jasmine.createSpy('modelChange callback');
downEl.click();
Expand All @@ -184,27 +178,31 @@ describe('StepperComponent', () => {
@Component({
selector: 'test-stepper',
template: `
<Stepper [defaultValue]="defaultValue"
[value]="value"
[min]="min"
[max]="max"
[step]="step"
[showNumber]="showNumber"
[disabled]="disabled"
[readOnly]="readOnly"
(onChange)="change($event)">
</Stepper>
<Stepper [defaultValue]="defaultValue"
[ngModel]="modelValue"
[min]="min"
[max]="max"
[step]="step"
[showNumber]="showNumber"
[disabled]="disabled"
[readOnly]="readOnly"
(ngModelChange)="modelChange($event)">
</Stepper>
`
<Stepper
[defaultValue]="defaultValue"
[value]="value"
[min]="min"
[max]="max"
[step]="step"
[showNumber]="showNumber"
[disabled]="disabled"
[readOnly]="readOnly"
(onChange)="change($event)"
>
</Stepper>
<Stepper
[defaultValue]="defaultValue"
[ngModel]="modelValue"
[min]="min"
[max]="max"
[step]="step"
[showNumber]="showNumber"
[disabled]="disabled"
[readOnly]="readOnly"
(ngModelChange)="modelChange($event)"
>
</Stepper>
`
})
export class TestStepperComponent {
max = Infinity;
Expand Down
67 changes: 53 additions & 14 deletions components/stepper/stepper.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
useExisting: forwardRef(() => Stepper),
multi: true
}
],
]
})
export class Stepper implements OnChanges, ControlValueAccessor {
prefixCls: string = 'am-stepper';
Expand Down Expand Up @@ -53,9 +53,6 @@ export class Stepper implements OnChanges, ControlValueAccessor {
this._value = v;
}
@Input()
get step(): number {
return this._step;
}
set step(value) {
this._step = value;
}
Expand Down Expand Up @@ -106,13 +103,13 @@ export class Stepper implements OnChanges, ControlValueAccessor {

onIncrease() {
if (!this._upDisabled) {
this._value = this._value + this._step;
this._value = this.plus(this._value, this._step);
this.onChange.emit(this._value);
this.onChangeFn(this._value);
if (this._value + this._step > this._max) {
if (this.plus(this._value, this._step) > this._max) {
this._upDisabled = true;
}
if (this._value - this._step >= this._min) {
if (this.minus(this._value, this._step) >= this._min) {
this._downDisabled = false;
}
this._isUpClick = true;
Expand All @@ -126,13 +123,13 @@ export class Stepper implements OnChanges, ControlValueAccessor {

onDecrease() {
if (!this._downDisabled) {
this._value = this._value - this._step;
this._value = this.minus(this._value, this._step);
this.onChange.emit(this._value);
this.onChangeFn(this._value);
if (this._value - this._step < this._min) {
if (this.minus(this._value, this._step) < this._min) {
this._downDisabled = true;
}
if (this._value + this._step <= this._max) {
if (this.plus(this._value, this._step) <= this._max) {
this._upDisabled = false;
}
this._isDownClick = true;
Expand Down Expand Up @@ -169,10 +166,10 @@ export class Stepper implements OnChanges, ControlValueAccessor {
}

ngOnChanges() {
if (this._value + this._step > this._max) {
if (this.plus(this._value, this._step) > this._max) {
this._upDisabled = true;
}
if (this._value - this._step < this._min) {
if (this.minus(this._value, this._step) < this._min) {
this._downDisabled = true;
}
this.setCls();
Expand All @@ -183,11 +180,53 @@ export class Stepper implements OnChanges, ControlValueAccessor {
this.ngOnChanges();
}

registerOnChange(fn: (value: number) => void): void {
registerOnChange(fn: (value: number) => void): void {
this.onChangeFn = fn;
}

registerOnTouched(fn: (value: number) => void): void {
registerOnTouched(fn: (value: number) => void): void {
this.onTouchFn = fn;
}

plus(num1: number, num2: number): number {
if (num1 === undefined || num1 === null || num2 === undefined || num2 === null) {
return;
}
const baseNum = Math.pow(10, Math.max(this.digitLength(num1), this.digitLength(num2)));
return (this.times(num1, baseNum) + this.times(num2, baseNum)) / baseNum;
}

minus(num1: number, num2: number): number {
if (num1 === undefined || num1 === null || num2 === undefined || num2 === null) {
return;
}
const baseNum = Math.pow(10, Math.max(this.digitLength(num1), this.digitLength(num2)));
return (this.times(num1, baseNum) - this.times(num2, baseNum)) / baseNum;
}

digitLength(num: number): number {
const eSplit = num.toString().split(/[eE]/);
const len = (eSplit[0].split('.')[1] || '').length - +(eSplit[1] || 0);
return len > 0 ? len : 0;
}

times(num1: number, num2: number): number {
const num1Changed = this.floatToFixed(num1);
const num2Changed = this.floatToFixed(num2);
const baseNum = this.digitLength(num1) + this.digitLength(num2);
const leftValue = num1Changed * num2Changed;
return leftValue / Math.pow(10, baseNum);
}

floatToFixed(num: number): number {
if (num.toString().indexOf('e') === -1) {
return Number(num.toString().replace('.', ''));
}
const dLen = this.digitLength(num);
return dLen > 0 ? this.strip(num * Math.pow(10, dLen)) : num;
}

strip(num: number, precision = 12): number {
return +parseFloat(num.toPrecision(precision));
}
}

0 comments on commit 5cd1f6c

Please sign in to comment.