ngx-numeric-counter
Version:
Angular component for numeric input with increment and decrement buttons.
95 lines • 12.3 kB
JavaScript
import { CommonModule } from '@angular/common';
import { Component, forwardRef, Input } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
export class NgxNumericCounterComponent {
constructor() {
this.min = Number.NEGATIVE_INFINITY;
this.max = Number.POSITIVE_INFINITY;
this.step = 1;
this.disabled = false;
this.buttonClass = '';
this.inputClass = '';
this.containerClass = '';
this.value = 0;
this.onChange = (value) => { };
this.onTouched = () => { };
}
writeValue(value) {
this.value = value ?? 0;
}
registerOnChange(fn) {
this.onChange = fn;
}
registerOnTouched(fn) {
this.onTouched = fn;
}
setDisabledState(isDisabled) {
this.disabled = isDisabled;
}
increment() {
if (this.disabled)
return;
const newValue = this.value + this.step;
if (newValue <= this.max) {
this.value = newValue;
this.onChange(this.value);
this.onTouched();
}
}
decrement() {
if (this.disabled)
return;
const newValue = this.value - this.step;
if (newValue >= this.min) {
this.value = newValue;
this.onChange(this.value);
this.onTouched();
}
}
onInputChange(event) {
const val = +event.target.value;
if (!isNaN(val) && val >= this.min && val <= this.max) {
this.value = val;
this.onChange(this.value);
}
else if (event.target.value === '') {
this.value = 0;
this.onChange(this.value);
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NgxNumericCounterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: NgxNumericCounterComponent, isStandalone: true, selector: "ngx-numeric-counter", inputs: { min: "min", max: "max", step: "step", disabled: "disabled", buttonClass: "buttonClass", inputClass: "inputClass", containerClass: "containerClass" }, providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => NgxNumericCounterComponent),
multi: true,
},
], ngImport: i0, template: "<div class=\"counter-container\" [ngClass]=\"containerClass\">\n <button\n (click)=\"decrement()\"\n [disabled]=\"disabled || value <= min\"\n [ngClass]=\"buttonClass\"\n >\n -\n </button>\n\n <input\n type=\"number\"\n [value]=\"value\"\n (input)=\"onInputChange($event)\"\n [disabled]=\"disabled\"\n [ngClass]=\"inputClass\"\n />\n\n <button\n (click)=\"increment()\"\n [disabled]=\"disabled || value >= max\"\n [ngClass]=\"buttonClass\"\n >\n +\n </button>\n</div>\n", styles: [".counter-container{display:inline-flex;align-items:center;gap:4px}.counter-container button{width:32px;height:32px;font-weight:700;font-size:16px;cursor:pointer}.counter-container input{width:60px;text-align:center;padding:4px;font-size:16px}.counter-container button:disabled{opacity:.5;cursor:not-allowed}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NgxNumericCounterComponent, decorators: [{
type: Component,
args: [{ selector: 'ngx-numeric-counter', standalone: true, imports: [CommonModule], providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => NgxNumericCounterComponent),
multi: true,
},
], template: "<div class=\"counter-container\" [ngClass]=\"containerClass\">\n <button\n (click)=\"decrement()\"\n [disabled]=\"disabled || value <= min\"\n [ngClass]=\"buttonClass\"\n >\n -\n </button>\n\n <input\n type=\"number\"\n [value]=\"value\"\n (input)=\"onInputChange($event)\"\n [disabled]=\"disabled\"\n [ngClass]=\"inputClass\"\n />\n\n <button\n (click)=\"increment()\"\n [disabled]=\"disabled || value >= max\"\n [ngClass]=\"buttonClass\"\n >\n +\n </button>\n</div>\n", styles: [".counter-container{display:inline-flex;align-items:center;gap:4px}.counter-container button{width:32px;height:32px;font-weight:700;font-size:16px;cursor:pointer}.counter-container input{width:60px;text-align:center;padding:4px;font-size:16px}.counter-container button:disabled{opacity:.5;cursor:not-allowed}\n"] }]
}], propDecorators: { min: [{
type: Input
}], max: [{
type: Input
}], step: [{
type: Input
}], disabled: [{
type: Input
}], buttonClass: [{
type: Input
}], inputClass: [{
type: Input
}], containerClass: [{
type: Input
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LW51bWVyaWMtY291bnRlci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtbnVtZXJpYy1jb3VudGVyL3NyYy9saWIvbmd4LW51bWVyaWMtY291bnRlci5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtbnVtZXJpYy1jb3VudGVyL3NyYy9saWIvbmd4LW51bWVyaWMtY291bnRlci5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsS0FBSyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzdELE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDOzs7QUFnQm5ELE1BQU0sT0FBTywwQkFBMEI7SUFkdkM7UUFlVyxRQUFHLEdBQUcsTUFBTSxDQUFDLGlCQUFpQixDQUFDO1FBQy9CLFFBQUcsR0FBRyxNQUFNLENBQUMsaUJBQWlCLENBQUM7UUFDL0IsU0FBSSxHQUFHLENBQUMsQ0FBQztRQUNULGFBQVEsR0FBRyxLQUFLLENBQUM7UUFDakIsZ0JBQVcsR0FBRyxFQUFFLENBQUM7UUFDakIsZUFBVSxHQUFHLEVBQUUsQ0FBQztRQUNoQixtQkFBYyxHQUFHLEVBQUUsQ0FBQztRQUU3QixVQUFLLEdBQUcsQ0FBQyxDQUFDO1FBRVYsYUFBUSxHQUFHLENBQUMsS0FBYSxFQUFFLEVBQUUsR0FBRSxDQUFDLENBQUM7UUFDakMsY0FBUyxHQUFHLEdBQUcsRUFBRSxHQUFFLENBQUMsQ0FBQztLQWdEdEI7SUE5Q0MsVUFBVSxDQUFDLEtBQWE7UUFDdEIsSUFBSSxDQUFDLEtBQUssR0FBRyxLQUFLLElBQUksQ0FBQyxDQUFDO0lBQzFCLENBQUM7SUFFRCxnQkFBZ0IsQ0FBQyxFQUFPO1FBQ3RCLElBQUksQ0FBQyxRQUFRLEdBQUcsRUFBRSxDQUFDO0lBQ3JCLENBQUM7SUFFRCxpQkFBaUIsQ0FBQyxFQUFPO1FBQ3ZCLElBQUksQ0FBQyxTQUFTLEdBQUcsRUFBRSxDQUFDO0lBQ3RCLENBQUM7SUFFRCxnQkFBZ0IsQ0FBQyxVQUFtQjtRQUNsQyxJQUFJLENBQUMsUUFBUSxHQUFHLFVBQVUsQ0FBQztJQUM3QixDQUFDO0lBRUQsU0FBUztRQUNQLElBQUksSUFBSSxDQUFDLFFBQVE7WUFBRSxPQUFPO1FBQzFCLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQztRQUN4QyxJQUFJLFFBQVEsSUFBSSxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7WUFDekIsSUFBSSxDQUFDLEtBQUssR0FBRyxRQUFRLENBQUM7WUFDdEIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDMUIsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1FBQ25CLENBQUM7SUFDSCxDQUFDO0lBRUQsU0FBUztRQUNQLElBQUksSUFBSSxDQUFDLFFBQVE7WUFBRSxPQUFPO1FBQzFCLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQztRQUN4QyxJQUFJLFFBQVEsSUFBSSxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7WUFDekIsSUFBSSxDQUFDLEtBQUssR0FBRyxRQUFRLENBQUM7WUFDdEIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDMUIsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1FBQ25CLENBQUM7SUFDSCxDQUFDO0lBRUQsYUFBYSxDQUFDLEtBQVU7UUFDdEIsTUFBTSxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQztRQUNoQyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEdBQUcsSUFBSSxJQUFJLENBQUMsR0FBRyxJQUFJLEdBQUcsSUFBSSxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7WUFDdEQsSUFBSSxDQUFDLEtBQUssR0FBRyxHQUFHLENBQUM7WUFDakIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDNUIsQ0FBQzthQUFNLElBQUksS0FBSyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEtBQUssRUFBRSxFQUFFLENBQUM7WUFDckMsSUFBSSxDQUFDLEtBQUssR0FBRyxDQUFDLENBQUM7WUFDZixJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUM1QixDQUFDO0lBQ0gsQ0FBQzsrR0EzRFUsMEJBQTBCO21HQUExQiwwQkFBMEIsa09BVjFCO1lBQ1Q7Z0JBQ0UsT0FBTyxFQUFFLGlCQUFpQjtnQkFDMUIsV0FBVyxFQUFFLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQywwQkFBMEIsQ0FBQztnQkFDekQsS0FBSyxFQUFFLElBQUk7YUFDWjtTQUNGLDBCQ2RILHNnQkF5QkEsOFdEbEJZLFlBQVk7OzRGQVdYLDBCQUEwQjtrQkFkdEMsU0FBUzsrQkFDRSxxQkFBcUIsY0FDbkIsSUFBSSxXQUNQLENBQUMsWUFBWSxDQUFDLGFBQ1o7d0JBQ1Q7NEJBQ0UsT0FBTyxFQUFFLGlCQUFpQjs0QkFDMUIsV0FBVyxFQUFFLFVBQVUsQ0FBQyxHQUFHLEVBQUUsMkJBQTJCLENBQUM7NEJBQ3pELEtBQUssRUFBRSxJQUFJO3lCQUNaO3FCQUNGOzhCQUtRLEdBQUc7c0JBQVgsS0FBSztnQkFDRyxHQUFHO3NCQUFYLEtBQUs7Z0JBQ0csSUFBSTtzQkFBWixLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0csV0FBVztzQkFBbkIsS0FBSztnQkFDRyxVQUFVO3NCQUFsQixLQUFLO2dCQUNHLGNBQWM7c0JBQXRCLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgQ29tcG9uZW50LCBmb3J3YXJkUmVmLCBJbnB1dCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgTkdfVkFMVUVfQUNDRVNTT1IgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ25neC1udW1lcmljLWNvdW50ZXInLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbQ29tbW9uTW9kdWxlXSxcbiAgcHJvdmlkZXJzOiBbXG4gICAge1xuICAgICAgcHJvdmlkZTogTkdfVkFMVUVfQUNDRVNTT1IsXG4gICAgICB1c2VFeGlzdGluZzogZm9yd2FyZFJlZigoKSA9PiBOZ3hOdW1lcmljQ291bnRlckNvbXBvbmVudCksXG4gICAgICBtdWx0aTogdHJ1ZSxcbiAgICB9LFxuICBdLFxuICB0ZW1wbGF0ZVVybDogJ25neC1udW1lcmljLWNvdW50ZXIuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybDogJ25neC1udW1lcmljLWNvdW50ZXIuY29tcG9uZW50LnNjc3MnLFxufSlcbmV4cG9ydCBjbGFzcyBOZ3hOdW1lcmljQ291bnRlckNvbXBvbmVudCB7XG4gIEBJbnB1dCgpIG1pbiA9IE51bWJlci5ORUdBVElWRV9JTkZJTklUWTtcbiAgQElucHV0KCkgbWF4ID0gTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZO1xuICBASW5wdXQoKSBzdGVwID0gMTtcbiAgQElucHV0KCkgZGlzYWJsZWQgPSBmYWxzZTtcbiAgQElucHV0KCkgYnV0dG9uQ2xhc3MgPSAnJztcbiAgQElucHV0KCkgaW5wdXRDbGFzcyA9ICcnO1xuICBASW5wdXQoKSBjb250YWluZXJDbGFzcyA9ICcnO1xuXG4gIHZhbHVlID0gMDtcblxuICBvbkNoYW5nZSA9ICh2YWx1ZTogbnVtYmVyKSA9PiB7fTtcbiAgb25Ub3VjaGVkID0gKCkgPT4ge307XG5cbiAgd3JpdGVWYWx1ZSh2YWx1ZTogbnVtYmVyKTogdm9pZCB7XG4gICAgdGhpcy52YWx1ZSA9IHZhbHVlID8/IDA7XG4gIH1cblxuICByZWdpc3Rlck9uQ2hhbmdlKGZuOiBhbnkpOiB2b2lkIHtcbiAgICB0aGlzLm9uQ2hhbmdlID0gZm47XG4gIH1cblxuICByZWdpc3Rlck9uVG91Y2hlZChmbjogYW55KTogdm9pZCB7XG4gICAgdGhpcy5vblRvdWNoZWQgPSBmbjtcbiAgfVxuXG4gIHNldERpc2FibGVkU3RhdGUoaXNEaXNhYmxlZDogYm9vbGVhbik6IHZvaWQge1xuICAgIHRoaXMuZGlzYWJsZWQgPSBpc0Rpc2FibGVkO1xuICB9XG5cbiAgaW5jcmVtZW50KCkge1xuICAgIGlmICh0aGlzLmRpc2FibGVkKSByZXR1cm47XG4gICAgY29uc3QgbmV3VmFsdWUgPSB0aGlzLnZhbHVlICsgdGhpcy5zdGVwO1xuICAgIGlmIChuZXdWYWx1ZSA8PSB0aGlzLm1heCkge1xuICAgICAgdGhpcy52YWx1ZSA9IG5ld1ZhbHVlO1xuICAgICAgdGhpcy5vbkNoYW5nZSh0aGlzLnZhbHVlKTtcbiAgICAgIHRoaXMub25Ub3VjaGVkKCk7XG4gICAgfVxuICB9XG5cbiAgZGVjcmVtZW50KCkge1xuICAgIGlmICh0aGlzLmRpc2FibGVkKSByZXR1cm47XG4gICAgY29uc3QgbmV3VmFsdWUgPSB0aGlzLnZhbHVlIC0gdGhpcy5zdGVwO1xuICAgIGlmIChuZXdWYWx1ZSA+PSB0aGlzLm1pbikge1xuICAgICAgdGhpcy52YWx1ZSA9IG5ld1ZhbHVlO1xuICAgICAgdGhpcy5vbkNoYW5nZSh0aGlzLnZhbHVlKTtcbiAgICAgIHRoaXMub25Ub3VjaGVkKCk7XG4gICAgfVxuICB9XG5cbiAgb25JbnB1dENoYW5nZShldmVudDogYW55KSB7XG4gICAgY29uc3QgdmFsID0gK2V2ZW50LnRhcmdldC52YWx1ZTtcbiAgICBpZiAoIWlzTmFOKHZhbCkgJiYgdmFsID49IHRoaXMubWluICYmIHZhbCA8PSB0aGlzLm1heCkge1xuICAgICAgdGhpcy52YWx1ZSA9IHZhbDtcbiAgICAgIHRoaXMub25DaGFuZ2UodGhpcy52YWx1ZSk7XG4gICAgfSBlbHNlIGlmIChldmVudC50YXJnZXQudmFsdWUgPT09ICcnKSB7XG4gICAgICB0aGlzLnZhbHVlID0gMDtcbiAgICAgIHRoaXMub25DaGFuZ2UodGhpcy52YWx1ZSk7XG4gICAgfVxuICB9XG59XG4iLCI8ZGl2IGNsYXNzPVwiY291bnRlci1jb250YWluZXJcIiBbbmdDbGFzc109XCJjb250YWluZXJDbGFzc1wiPlxuICA8YnV0dG9uXG4gICAgKGNsaWNrKT1cImRlY3JlbWVudCgpXCJcbiAgICBbZGlzYWJsZWRdPVwiZGlzYWJsZWQgfHwgdmFsdWUgPD0gbWluXCJcbiAgICBbbmdDbGFzc109XCJidXR0b25DbGFzc1wiXG4gID5cbiAgICAtXG4gIDwvYnV0dG9uPlxuXG4gIDxpbnB1dFxuICAgIHR5cGU9XCJudW1iZXJcIlxuICAgIFt2YWx1ZV09XCJ2YWx1ZVwiXG4gICAgKGlucHV0KT1cIm9uSW5wdXRDaGFuZ2UoJGV2ZW50KVwiXG4gICAgW2Rpc2FibGVkXT1cImRpc2FibGVkXCJcbiAgICBbbmdDbGFzc109XCJpbnB1dENsYXNzXCJcbiAgLz5cblxuICA8YnV0dG9uXG4gICAgKGNsaWNrKT1cImluY3JlbWVudCgpXCJcbiAgICBbZGlzYWJsZWRdPVwiZGlzYWJsZWQgfHwgdmFsdWUgPj0gbWF4XCJcbiAgICBbbmdDbGFzc109XCJidXR0b25DbGFzc1wiXG4gID5cbiAgICArXG4gIDwvYnV0dG9uPlxuPC9kaXY+XG4iXX0=