diff --git a/components/stepper/demo/basic.ts b/components/stepper/demo/basic.ts index 6a735adf..a379b542 100644 --- a/components/stepper/demo/basic.ts +++ b/components/stepper/demo/basic.ts @@ -4,25 +4,36 @@ import { Component } from '@angular/core'; selector: 'demo-stepper-basic', template: ` - Show number value Show number value + Decimal step Disabled + ReadOnly - + + + + - - + + `, styles: [``] }) export class DemoStepperBasicComponent { - value = 3; - value1 = 6; + value = 0; + decimalValue = 6; constructor() {} diff --git a/components/stepper/stepper.component.html b/components/stepper/stepper.component.html index ca390121..78f0b112 100644 --- a/components/stepper/stepper.component.html +++ b/components/stepper/stepper.component.html @@ -20,8 +20,9 @@
diff --git a/components/stepper/stepper.component.spec.ts b/components/stepper/stepper.component.spec.ts index a4c5ad91..7928df9f 100644 --- a/components/stepper/stepper.component.spec.ts +++ b/components/stepper/stepper.component.spec.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { By } from '@angular/platform-browser'; -import { ComponentFixture, TestBed, fakeAsync, waitForAsync } from '@angular/core/testing'; +import { ComponentFixture, TestBed, fakeAsync, waitForAsync, tick } from '@angular/core/testing'; import { StepperModule } from './stepper.module'; describe('StepperComponent', () => { @@ -12,12 +12,14 @@ describe('StepperComponent', () => { let upButton; let downButton; let inputEle; - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - declarations: [TestStepperComponent], - imports: [StepperModule, FormsModule] - }).compileComponents(); - })); + beforeEach( + waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [TestStepperComponent], + imports: [StepperModule, FormsModule] + }).compileComponents(); + }) + ); beforeEach(() => { fixture = TestBed.createComponent(TestStepperComponent); @@ -42,7 +44,6 @@ describe('StepperComponent', () => { 'up-disabled' ); }); - it('should min work', () => { component.min = 9; component.value = 9; @@ -68,8 +69,7 @@ describe('StepperComponent', () => { 'up-disabled' ); }); - - it('should dowDisabled work', () => { + it('should downDisabled work', () => { component.min = 5; component.value = 9; component.step = 3; @@ -83,29 +83,6 @@ describe('StepperComponent', () => { ); }); - it('should defaultValue work', () => { - component.defaultValue = 11; - fixture.detectChanges(); - expect(component.defaultValue).toBe(11, 'value == defaultValue'); - }); - it('should step work', () => { - component.value = 1e-13; - component.step = 2; - fixture.detectChanges(); - downButton.click(); - expect(component.value).toBe(-1.9999999999999, 'step is 2'); - component.step = 3; - fixture.detectChanges(); - upButton.click(); - 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'); - }); it('should disabled work', () => { expect(stepperEle.nativeElement.classList).not.toContain('am-stepper-disabled', 'not contain am-stepper-disabled'); component.disabled = true; @@ -150,27 +127,79 @@ describe('StepperComponent', () => { expect(stepperEle.nativeElement.classList).not.toContain('am-stepper-disabled', 'contain am-stepper-disabled'); }); - it('should readOnly work', fakeAsync(() => { + component.readOnly = true; + fixture.detectChanges(); + expect(inputEle.getAttribute('readonly')).not.toBeNull('readonly is null'); + })); + + it('should defaultValue work', () => { + component.defaultValue = 11; + fixture.detectChanges(); + expect(component.defaultValue).toBe(11, 'value == defaultValue'); + }); + it('should step work', () => { + component.value = 1e-13; + component.step = 2; + fixture.detectChanges(); + downButton.click(); + expect(component.value).toBe(-1.9999999999999, 'step is 2'); + component.step = 3; + fixture.detectChanges(); + upButton.click(); + 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'); + }); + + it('should only input numbers work', fakeAsync(() => { + inputEle.value = 'ssssss'; + inputEle.dispatchEvent(new UIEvent('input')); + tick(0); + expect(component.value).toBe(0, 'input ssssss'); + + inputEle.value = '测试中文'; + inputEle.dispatchEvent(new UIEvent('input')); + tick(0); + expect(component.value).toBe(0, 'input 测试中文'); + + inputEle.value = 's1s.s2s.s3s'; + inputEle.dispatchEvent(new UIEvent('input')); + tick(0); + expect(component.value).toBe(123, 'input s1s.s2s.s3s'); + + inputEle.value = '-1-2-3'; + inputEle.dispatchEvent(new UIEvent('input')); + tick(0); + expect(component.value).toBe(-123, 'input -1-2-3'); + })); + + it('should blur check work', fakeAsync(() => { component.max = 20; component.min = 10; fixture.detectChanges(); inputEle.value = 34; inputEle.dispatchEvent(new UIEvent('input')); - expect(component.value).toBe(20, 'set input'); + tick(0); + inputEle.dispatchEvent(new Event('blur')); + expect(component.value).toBe(20, 'check max input'); inputEle.value = 4; inputEle.dispatchEvent(new UIEvent('input')); - expect(component.value).toBe(10, 'set input'); + tick(0); + inputEle.dispatchEvent(new Event('blur')); + expect(component.value).toBe(10, 'check min input'); inputEle.value = 15; inputEle.dispatchEvent(new UIEvent('input')); - expect(component.value).toBe(15, 'set input'); - - component.readOnly = true; - fixture.detectChanges(); - expect(inputEle.getAttribute('readonly')).not.toBeNull('readonly is null'); + tick(0); + inputEle.dispatchEvent(new Event('blur')); + expect(component.value).toBe(15, 'check normal input'); })); it('should onChange work', () => { diff --git a/components/stepper/stepper.component.ts b/components/stepper/stepper.component.ts index e211226e..8d93ecb4 100644 --- a/components/stepper/stepper.component.ts +++ b/components/stepper/stepper.component.ts @@ -30,6 +30,7 @@ export class StepperComponent implements OnChanges, ControlValueAccessor { private _downDisabled: boolean = false; private _isUpClick: boolean = false; private _isDownClick: boolean = false; + private _inputLock = false; @Input() get max(): number { @@ -141,20 +142,72 @@ export class StepperComponent implements OnChanges, ControlValueAccessor { } } + compositionStart() { + this._inputLock = true; + } + + compositionEnd() { + this._inputLock = false; + } + inputChange(event) { - const value = event; - this._value = value ? +value : 0; + // 'compositionend' is earlier than ngModelChange, Therefore use timer to make ngModelChange runs after 'compositionend' event + setTimeout(() => { + if (this._inputLock) { + return; + } + + const allowDecimal = this._step % 1 !== 0; + const allowNegative = this._min < 0; + let decimalFlag = false; + let negativeFlag = false; + let value = event.toString().replace(/\D/g, (match, index, str) => { + if (allowDecimal && match === '.' && !decimalFlag) { + decimalFlag = true; + return '.'; + } + if (allowNegative && match === '-' && !negativeFlag) { + negativeFlag = true; + return '-'; + } + return ''; + }); + + if (negativeFlag && value.indexOf('-') > 0) { + value = value.replace(/-/g, ''); + } + + if (!isNaN(value)) { + this._value = +value; + this._upDisabled = this.plus(this._value, this._step) > this._max ? true : false; + this._downDisabled = this.minus(this._value, this._step) < this._min ? true : false; + } + + this.setCls(); + this.onChange.emit(this._value); + this.onChangeFn(this._value); + }, 0); + } + + inputBlur() { + let value = +this._value; + if (+this._value === -0) { + value = 0; + } if (this._value < this._min) { - this._value = this._min; + value = this._min; + } else if (this._value > this._max) { + value = this._max; } - if (this._value > this._max) { - this._value = this._max; + + const len = this._step.toString().length - this._step.toString().indexOf('.') - 1; + value = +value.toFixed(len); + + if (value !== this._value) { + this._value = value; + this.onChange.emit(this._value); + this.onChangeFn(this._value); } - this._upDisabled = this.plus(this._value, this._step) > this._max ? true : false; - this._downDisabled = this.minus(this._value, this._step) < this._min ? true : false; - this.setCls(); - this.onChange.emit(this._value); - this.onChangeFn(this._value); } setCls() {