input-number refactor #1311
gitea/salix/master This commit looks good Details

This commit is contained in:
Joan Sanchez 2019-04-09 13:18:55 +02:00
parent b4f9b2fc3b
commit a6308c7f1e
16 changed files with 132 additions and 206 deletions

View File

@ -5,7 +5,7 @@
<vn-icon-button <vn-icon-button
ng-if="$ctrl.displayControls" ng-if="$ctrl.displayControls"
icon="remove" icon="remove"
ng-click="$ctrl.remove()" ng-click="$ctrl.stepDown()"
tabindex="-1" tabindex="-1"
translate-attr="{title: 'Remove'}"> translate-attr="{title: 'Remove'}">
</vn-icon-button> </vn-icon-button>
@ -30,7 +30,7 @@
<vn-icon-button <vn-icon-button
ng-if="$ctrl.displayControls" ng-if="$ctrl.displayControls"
icon="add" icon="add"
ng-click="$ctrl.add()" ng-click="$ctrl.stepUp()"
tabindex="-1" tabindex="-1"
translate-attr="{title: 'Add'}"> translate-attr="{title: 'Add'}">
</vn-icon-button> </vn-icon-button>

View File

@ -5,9 +5,11 @@ import './style.scss';
export default class InputNumber extends Input { export default class InputNumber extends Input {
constructor($element, $scope, $attrs, vnTemplate) { constructor($element, $scope, $attrs, vnTemplate) {
super($element, $scope); super($element, $scope);
vnTemplate.normalizeInputAttrs($attrs); this.displayControls = false;
this.displayControls = true;
this.hasFocus = false; this.hasFocus = false;
vnTemplate.normalizeInputAttrs($attrs);
this.registerEvents(); this.registerEvents();
} }
@ -15,8 +17,11 @@ export default class InputNumber extends Input {
* Registers all event emitters * Registers all event emitters
*/ */
registerEvents() { registerEvents() {
this.input.addEventListener('change', () => { this.input.addEventListener('change', event => {
this.validateValue(); if (!isNaN(this.value))
this.input.value = this.value;
this.emit('change', {event});
}); });
this.input.addEventListener('focus', event => { this.input.addEventListener('focus', event => {
@ -24,80 +29,118 @@ export default class InputNumber extends Input {
}); });
} }
/**
* Gets current value
*/
get value() { get value() {
return this._value; return this._value;
} }
/**
* Sets input value
*
* @param {Number} value - Value
*/
set value(value) { set value(value) {
this._value = value; this._value = value;
this.hasValue = this._value !== null; this.hasValue = this._value !== null;
this.input.value = this._value;
if (this.hasValue) this.element.classList.add('not-empty'); if (this.hasValue)
else this.element.classList.remove('not-empty'); this.element.classList.add('not-empty');
else
this.element.classList.remove('not-empty');
this.element.querySelector('.infix').classList.remove('invalid', 'validated'); this.validateValue();
} }
/**
* Gets max value
*/
get max() { get max() {
return this.input.max; return this.input.max;
} }
/**
* Sets max allowed value
*
* @param {Number} value - Value
*/
set max(value) { set max(value) {
if (value) if (value) this.input.max = value;
this.input.max = value;
} }
/**
* Gets min value
*/
get min() { get min() {
return this.input.min; return this.input.min;
} }
/**
* Sets min allowed value
*
* @param {Number} value - Value
*/
set min(value) { set min(value) {
if (!value) value = 0; if (!value) value = 0;
this.input.min = value; this.input.min = value;
} }
/**
* Gets min step value
*/
get step() { get step() {
return parseFloat(this.input.step); return parseFloat(this.input.step);
} }
/**
* Sets min step value
*
* @param {Number} value - Value
*/
set step(value) { set step(value) {
this.input.step = value; this.input.step = value;
} }
/**
* Increases the input value
*/
stepUp() {
this.input.stepUp();
}
/**
* Decreases the input value
*/
stepDown() {
this.input.stepDown();
}
/**
* Validates a valid input value
*
* @return {Boolean} - True if has a valid value
*/
hasValidValue() {
return this.input.checkValidity();
}
/**
* Changes the input element
* if has a validation error
*/
validateValue() { validateValue() {
if ((this.validate() !== undefined && !this.validate()) || if (!this.hasValidValue()) {
(this.max && this.value > this.max) || this.element.querySelector('.infix')
(this.min && this.value < this.min) || .classList.add('invalid', 'validated');
(this.displayControls && (this.step && this.value % this.step != 0))) } else {
this.$element[0].querySelector('.infix').classList.add('invalid', 'validated'); this.element.querySelector('.infix')
.classList.remove('invalid', 'validated');
}
if (this.onChange)
this.onChange();
}
add() {
if (this.step && this.value % this.step != 0)
this.value += (this.step - this.value % this.step);
else
this.value += this.step;
this.validateValue();
}
remove() {
if (this.step && this.value % this.step != 0)
this.value -= (this.step + this.value % this.step);
else
this.value -= this.step;
this.validateValue();
} }
} }
InputNumber.$inject = ['$element', '$scope', '$attrs', 'vnTemplate', '$transclude']; InputNumber.$inject = ['$element', '$scope', '$attrs', 'vnTemplate'];
ngModule.component('vnInputNumber', { ngModule.component('vnInputNumber', {
template: require('./index.html'), template: require('./index.html'),

View File

@ -12,144 +12,55 @@ describe('Component vnInputNumber', () => {
beforeEach(angular.mock.inject(($componentController, $rootScope) => { beforeEach(angular.mock.inject(($componentController, $rootScope) => {
$scope = $rootScope.$new(); $scope = $rootScope.$new();
$attrs = {}; $attrs = {};
$element = angular.element('<div><input><div class="infix invalid validated"><div class="rightIcons"></div></div>'); $element = angular.element('<div><input type="number"><div class="infix"><div class="rightIcons"></div></div>');
controller = $componentController('vnInputNumber', {$element, $scope, $attrs, $timeout, $transclude: () => {}}); controller = $componentController('vnInputNumber', {$element, $scope, $attrs, $timeout, $transclude: () => {}});
controller.input = $element[0].querySelector('input');
controller.validate = () => {};
})); }));
describe('value() setter', () => { describe('value() setter', () => {
it(`should set _value to a given value, add the class not-empty and remove invalid and validated`, () => { it(`should set a value, add the class 'not-empty' and then call validateValue() method`, () => {
controller.value = 'pepino'; spyOn(controller, 'validateValue');
controller.value = 10;
let classes = controller.element.classList.toString(); let classes = controller.element.classList.toString();
expect(classes).toContain('not-empty'); expect(classes).toContain('not-empty');
expect(controller._value).toEqual('pepino'); expect(controller.validateValue).toHaveBeenCalledWith();
classes = controller.element.querySelector('.infix').classList.toString();
expect(classes).not.toContain('invalid validated');
}); });
it(`should set _value to a given value and not add the class not-empty if the given value is null`, () => { it(`should set an empty value, remove the class 'not-empty' and then call validateValue() method`, () => {
spyOn(controller, 'validateValue');
controller.value = null; controller.value = null;
let classes = controller.element.classList.toString(); let classes = controller.element.classList.toString();
expect(classes).not.toContain('not-empty'); expect(classes).not.toContain('not-empty');
expect(controller._value).toEqual(null); expect(controller.validateValue).toHaveBeenCalledWith();
});
});
describe('max() setter', () => {
it(`should set input.max to a given value`, () => {
controller.max = 10;
expect(controller.input.max).toEqual('10');
});
});
describe('min() setter', () => {
it(`should set input.min if theres a given value`, () => {
controller.min = 1;
expect(controller.input.min).toEqual('1');
});
it(`should set input.min to 0 if theres not a given value`, () => {
controller.min = null;
expect(controller.input.min).toEqual('0');
});
});
describe('step() setter/getter', () => {
it(`should set input.step to a given value`, () => {
controller.step = 50;
expect(controller.input.step).toEqual('50');
});
it(`should return a number`, () => {
controller.step = 50;
expect(controller.step).toEqual(50);
expect(typeof controller.step).toEqual('number');
}); });
}); });
describe('validateValue()', () => { describe('validateValue()', () => {
it(`should add the classes invalid and validated if the value is less than min`, () => { it(`should call hasValidValue() and not add the class invalid and validated`, () => {
controller.validate = () => {}; controller.input.min = 0;
controller.min = 0; controller.input.value = 10;
controller.value = -7;
controller.validateValue();
let classes = controller.element.querySelector('.infix').classList.toString(); let classes = controller.element.querySelector('.infix').classList.toString();
expect(classes).not.toContain('invalid validated'); expect(classes).not.toContain('invalid validated');
expect(controller.value).toEqual(-7);
controller.validateValue();
classes = controller.element.querySelector('.infix').classList.toString();
expect(classes).toContain('infix invalid validated');
}); });
it(`should add the classes invalid and validated if the value is greater than max`, () => { it(`should call hasValidValue() and add the class invalid and validated`, () => {
controller.validate = () => {}; controller.input.min = 0;
controller.max = 10; controller.input.value = -10;
controller.value = 15;
controller.validateValue();
let classes = controller.element.querySelector('.infix').classList.toString(); let classes = controller.element.querySelector('.infix').classList.toString();
expect(classes).not.toContain('invalid validated'); expect(classes).toContain('invalid validated');
expect(controller.value).toEqual(15);
controller.validateValue();
classes = controller.element.querySelector('.infix').classList.toString();
expect(classes).toContain('infix invalid validated');
});
it(`should add the classes invalid and validated if the value is not a valid step`, () => {
controller.validate = () => {};
controller.step = 5;
controller.value = 7;
let classes = controller.element.querySelector('.infix').classList.toString();
expect(classes).not.toContain('invalid validated');
expect(controller.value).toEqual(7);
controller.validateValue();
classes = controller.element.querySelector('.infix').classList.toString();
expect(classes).toContain('infix invalid validated');
});
it(`should add the classes invalid and validated if the function validate returns false`, () => {
controller.validate = () => {
return false;
};
controller.step = 5;
controller.value = 7;
let classes = controller.element.querySelector('.infix').classList.toString();
expect(classes).not.toContain('invalid validated');
expect(controller.value).toEqual(7);
controller.validateValue();
classes = controller.element.querySelector('.infix').classList.toString();
expect(classes).toContain('infix invalid validated');
});
});
describe('add()', () => {
it(`should set value to the next possible step and call validateValue`, () => {
spyOn(controller, 'validateValue');
controller.step = 50;
controller.value = -1;
controller.remove();
expect(controller.value).toEqual(-50);
expect(controller.validateValue).toHaveBeenCalledWith();
}); });
}); });
}); });

View File

@ -37,8 +37,7 @@
min="0" min="0"
step="1" step="1"
label="Traveling days" label="Traveling days"
field="$ctrl.zone.travelingDays" field="$ctrl.zone.travelingDays">
display-controls="false">
</vn-input-number> </vn-input-number>
<vn-input-time <vn-input-time
vn-two vn-two
@ -51,15 +50,13 @@
label="Price" label="Price"
field="$ctrl.zone.price" field="$ctrl.zone.price"
min="0.00" min="0.00"
step="0.10" step="0.10">
display-controls="false">
</vn-input-number> </vn-input-number>
<vn-input-number vn-one <vn-input-number vn-one
label="Bonus" label="Bonus"
field="$ctrl.zone.bonus" field="$ctrl.zone.bonus"
min="0.00" min="0.00"
step="0.10" step="0.10">
display-controls="false">
</vn-input-number> </vn-input-number>
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>

View File

@ -39,8 +39,7 @@
value="$ctrl.zone.travelingDays" value="$ctrl.zone.travelingDays"
step="1" step="1"
label="Traveling days" label="Traveling days"
field="$ctrl.zone.travelingDays" field="$ctrl.zone.travelingDays">
display-controls="false">
</vn-input-number> </vn-input-number>
<vn-input-time <vn-input-time
vn-two vn-two
@ -53,15 +52,13 @@
label="Price" label="Price"
field="$ctrl.zone.price" field="$ctrl.zone.price"
min="0.00" min="0.00"
step="0.10" step="0.10">
display-controls="false">
</vn-input-number> </vn-input-number>
<vn-input-number vn-one <vn-input-number vn-one
label="Bonus" label="Bonus"
field="$ctrl.zone.bonus" field="$ctrl.zone.bonus"
min="0.00" min="0.00"
step="0.10" step="0.10">
display-controls="false">
</vn-input-number> </vn-input-number>
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>

View File

@ -47,7 +47,6 @@
<vn-td> <vn-td>
<vn-input-number vn-focus min="0" step="1" <vn-input-number vn-focus min="0" step="1"
model="saleClaimed.quantity" model="saleClaimed.quantity"
display-controls="false"
on-change="$ctrl.setClaimedQuantity(saleClaimed.id, saleClaimed.quantity)"> on-change="$ctrl.setClaimedQuantity(saleClaimed.id, saleClaimed.quantity)">
</vn-input-number> </vn-input-number>
</vn-td> </vn-td>

View File

@ -2,14 +2,12 @@
<vn-card pad-large> <vn-card pad-large>
<vn-horizontal> <vn-horizontal>
<vn-input-number vn-one min="1" <vn-input-number vn-one min="1"
display-controls="false"
label="Credit" label="Credit"
model="$ctrl.creditClassification.credit", model="$ctrl.creditClassification.credit",
rule="creditInsurance.credit" rule="creditInsurance.credit"
vn-focus> vn-focus>
</vn-input-number> </vn-input-number>
<vn-input-number vn-one min="0" step="1" <vn-input-number vn-one min="0" step="1"
display-controls="false"
label="Grade" label="Grade"
model="$ctrl.creditClassification.grade" model="$ctrl.creditClassification.grade"
rule="CreditInsurance.grade"> rule="CreditInsurance.grade">

View File

@ -9,9 +9,8 @@
<vn-card pad-large> <vn-card pad-large>
<vn-horizontal> <vn-horizontal>
<vn-input-number vn-one min="0" <vn-input-number vn-one min="0"
display-controls="false"
label="Credit" label="Credit"
model="$ctrl.insurance.credit", model="$ctrl.insurance.credit"
rule="CreditInsurance.credit" rule="CreditInsurance.credit"
vn-focus> vn-focus>
</vn-input-number> </vn-input-number>
@ -23,7 +22,6 @@
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-input-number vn-one min="0" step="1" <vn-input-number vn-one min="0" step="1"
display-controls="false"
label="Grade" label="Grade"
model="$ctrl.insurance.grade" model="$ctrl.insurance.grade"
rule="CreditInsurance.grade"> rule="CreditInsurance.grade">

View File

@ -8,9 +8,7 @@
<form name="form" ng-submit="$ctrl.onSubmit()" compact> <form name="form" ng-submit="$ctrl.onSubmit()" compact>
<vn-card pad-large> <vn-card pad-large>
<vn-horizontal> <vn-horizontal>
<vn-input-number <vn-input-number vn-one min="0"
vn-one min="0"
display-controls="false"
label="Credit" label="Credit"
field="$ctrl.client.credit" field="$ctrl.client.credit"
vn-focus> vn-focus>

View File

@ -9,9 +9,8 @@
<vn-card pad-large> <vn-card pad-large>
<vn-horizontal> <vn-horizontal>
<vn-input-number vn-one vn-focus <vn-input-number vn-one vn-focus
display-controls="false"
label="Amount" label="Amount"
field="$ctrl.greuge.amount"> field="$ctrl.greuge.amount" step="0.01">
</vn-input-number> </vn-input-number>
<vn-date-picker vn-one <vn-date-picker vn-one
label="Date" label="Date"

View File

@ -8,30 +8,25 @@
<form name="form" ng-submit="$ctrl.onSubmit()" compact> <form name="form" ng-submit="$ctrl.onSubmit()" compact>
<vn-card pad-large> <vn-card pad-large>
<vn-horizontal> <vn-horizontal>
<vn-date-picker <vn-date-picker vn-one
vn-one
label="Since" label="Since"
model="$ctrl.recovery.started" model="$ctrl.recovery.started"
vn-focus vn-focus
ini-options="{enableTime: true}"> ini-options="{enableTime: true}">
</vn-date-picker> </vn-date-picker>
<vn-date-picker <vn-date-picker vn-one
vn-one
label="To" label="To"
model="$ctrl.recovery.finished" model="$ctrl.recovery.finished"
ini-options="{enableTime: true}"> ini-options="{enableTime: true}">
</vn-date-picker> </vn-date-picker>
<vn-input-number vn-one vn-focus <vn-input-number vn-one vn-focus
display-controls="false"
label="Amount" label="Amount"
field="$ctrl.recovery.amount"> field="$ctrl.recovery.amount" step="0.01">
</vn-input-number> </vn-input-number>
<vn-textfield <vn-input-number vn-one
vn-one
label="Period" label="Period"
field="$ctrl.recovery.period" field="$ctrl.recovery.period">
type="number"> </vn-input-number>
</vn-textfield>
</vn-horizontal> </vn-horizontal>
</vn-card> </vn-card>
<vn-button-bar> <vn-button-bar>

View File

@ -29,9 +29,8 @@
field="$ctrl.receipt.bankFk"> field="$ctrl.receipt.bankFk">
</vn-textfield> </vn-textfield>
<vn-input-number vn-one vn-focus <vn-input-number vn-one vn-focus
display-controls="false"
label="Amount" label="Amount"
field="$ctrl.receipt.amountPaid"> field="$ctrl.receipt.amountPaid" step="0.01">
</vn-input-number> </vn-input-number>
</vn-horizontal> </vn-horizontal>
</div> </div>

View File

@ -63,25 +63,21 @@
field="$ctrl.item.comment"> field="$ctrl.item.comment">
</vn-textfield> </vn-textfield>
<vn-input-number vn-one min="0" <vn-input-number vn-one min="0"
display-controls="false"
label="Size" label="Size"
field="$ctrl.item.size"> field="$ctrl.item.size">
</vn-input-number> </vn-input-number>
<vn-input-number vn-one min="0" <vn-input-number vn-one min="0"
display-controls="false"
label="stems" label="stems"
field="$ctrl.item.stems"> field="$ctrl.item.stems">
</vn-input-number> </vn-input-number>
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-input-number vn-one <vn-input-number vn-one min="0"
display-controls="false" min="0"
label="Density" label="Density"
field="$ctrl.item.density"> field="$ctrl.item.density">
</vn-input-number> </vn-input-number>
<!-- <vn-textfield vn-one label="compression" field="$ctrl.item.compression"></vn-textfield> --> <!-- <vn-textfield vn-one label="compression" field="$ctrl.item.compression"></vn-textfield> -->
<vn-input-number vn-one <vn-input-number vn-one min="0"
display-controls="false" min="0"
label="Relevancy" label="Relevancy"
field="$ctrl.item.relevancy"> field="$ctrl.item.relevancy">
</vn-input-number> </vn-input-number>

View File

@ -26,7 +26,6 @@
<tpl-item>{{itemFk}} : {{name}}</tpl-item> <tpl-item>{{itemFk}} : {{name}}</tpl-item>
</vn-autocomplete> </vn-autocomplete>
<vn-input-number vn-one min="1" step="1" <vn-input-number vn-one min="1" step="1"
display-controls="false"
label="Quantity" label="Quantity"
model="package.quantity" model="package.quantity"
rule="TicketPackaging.quantity"> rule="TicketPackaging.quantity">

View File

@ -22,13 +22,11 @@
</vn-autocomplete> </vn-autocomplete>
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-input-number vn-one min="1" <vn-input-number vn-one min="1"
display-controls="false"
label="Quantity" label="Quantity"
field="$ctrl.ticketRequest.quantity"> field="$ctrl.ticketRequest.quantity">
</vn-input-number> </vn-input-number>
<vn-input-number vn-one min="0" <vn-input-number vn-one min="0"
display-controls="false"
label="Price" label="Price"
field="$ctrl.ticketRequest.price"> field="$ctrl.ticketRequest.price">
</vn-input-number> </vn-input-number>

View File

@ -26,10 +26,9 @@
model="service.quantity" model="service.quantity"
rule="TicketService.quantity"> rule="TicketService.quantity">
</vn-input-number> </vn-input-number>
<vn-input-number vn-one step="1" <vn-input-number vn-one
display-controls="false"
label="Price" label="Price"
model="service.price"> model="service.price" step="0.01">
</vn-input-number> </vn-input-number>
<vn-autocomplete vn-one <vn-autocomplete vn-one
url="/api/TaxClasses" url="/api/TaxClasses"