File

src/number-input/number.component.ts

Description

Get started with importing the module:

Example :
import { NumberModule } from 'carbon-components-angular';

See demo

Implements

ControlValueAccessor

Metadata

Index

Properties
Methods
Inputs
Outputs
HostBindings
HostListeners
Accessors

Constructor

constructor(i18n: I18n)

Creates an instance of Number.

Parameters :
Name Type Optional
i18n I18n No

Inputs

ariaLabel
Type : string

Sets the arialabel for input

decorator
Type : TemplateRef<any>

Experimental: Optional decorator (e.g. AI label).

decrementLabel
Type : string | Observable
disabled
Type : boolean
Default value : false

Set to true for a disabled number input.

fluid
Type : boolean
Default value : false

Experimental: enable fluid state

helperText
Type : string | TemplateRef<any>

Sets the optional helper text.

hideLabel
Type : boolean
Default value : false

Visually hide the label while keeping it available for screen readers.

hideSteppers
Type : boolean
Default value : false

Hide the increment / decrement controls.

id
Type : string
Default value : `number-${NumberComponent.numberCount}`

The unique id for the number component.

incrementLabel
Type : string | Observable
inputMode
Type : string
Default value : "decimal"

inputmode attribute hint for mobile keyboards. Instruct the browser which keyboard to display on mobile devices. Defaults to decimal, but note that standard numeric keyboards vary across devices and operating systems.

https://css-tricks.com/everything-you-ever-wanted-to-know-about-inputmode/

invalid
Type : boolean
Default value : false

Set to true for an invalid number component.

invalidText
Type : string | TemplateRef<any>

Sets the invalid text.

label
Type : string | TemplateRef<any>

Sets the text inside the label tag.

max
Type : any
Default value : null

Sets the max attribute on the input element.

min
Type : any
Default value : null

Sets the min attribute on the input element.

pattern
Type : string

pattern attribute applied to the underlying <input>.

placeholder
Type : string
Default value : ""

Sets the placeholder attribute on the input element.

precision
Type : number

If step is a decimal, we may want precision to be set to go around floating point precision.

readonly
Type : boolean
Default value : false

Set to true for readonly state.

required
Type : boolean

Reflects the required attribute of the input element.

size
Type : "sm" | "md" | "lg"
Default value : "md"

Number input field render size

skeleton
Type : boolean
Default value : false

Set to true for a loading number component.

step
Type : number
Default value : 1

Sets the amount the number controls increment and decrement by.

theme
Type : "light" | "dark"
Default value : "dark"
value
Type : any

Sets the value attribute on the input element.

warn
Type : boolean
Default value : false

Set to true to show a warning (contents set by warningText)

warnText
Type : string | TemplateRef<any>

Sets the warning text

Outputs

change
Type : EventEmitter

Emits event notifying other classes when a change in state occurs in the input.

HostBindings

class.cds--form-item
Type : boolean
Default value : true
class.cds--number-input--fluid--disabled
Type : boolean
class.cds--number-input--fluid--focus
Type : boolean
class.cds--number-input--fluid--invalid
Type : boolean
class.cds--text-input--fluid__skeleton
Type : boolean

HostListeners

focusout
focusout()

Methods

emitChangeEvent
emitChangeEvent()

Creates a class of NumberChange to emit the change in the Number.

Returns : void
focusOut
focusOut()
Decorators :
@HostListener('focusout')
Returns : void
getDecrementLabel
getDecrementLabel()
Returns : Observable<string>
getIncrementLabel
getIncrementLabel()
Returns : Observable<string>
handleFocus
handleFocus(event: FocusEvent)
Parameters :
Name Type Optional
event FocusEvent No
Returns : void
Public isTemplate
isTemplate(value)
Parameters :
Name Optional
value No
Returns : boolean
onDecrement
onDecrement()

Subtracts step to the current value.

Returns : void
onIncrement
onIncrement()

Adds step to the current value.

Returns : void
onNumberInputChange
onNumberInputChange(event)
Parameters :
Name Optional
event No
Returns : void
Public registerOnChange
registerOnChange(fn: any)

Sets a method in order to propagate changes back to the form.

Parameters :
Name Type Optional
fn any No
Returns : void
Public registerOnTouched
registerOnTouched(fn: any)

Registers a callback to be triggered when the control has been touched.

Parameters :
Name Type Optional Description
fn any No

Callback to be triggered when the number input is touched.

Returns : void
setDisabledState
setDisabledState(isDisabled: boolean)

Sets the disabled state through the model

Parameters :
Name Type Optional
isDisabled boolean No
Returns : void
Public writeValue
writeValue(value: any)

This is the initial value set to the component

Parameters :
Name Type Optional Description
value any No

The input value.

Returns : void

Properties

Protected _decrementLabel
Type : Overridable
Default value : this.i18n.getOverridable("NUMBER.DECREMENT")
Protected _incrementLabel
Type : Overridable
Default value : this.i18n.getOverridable("NUMBER.INCREMENT")
Protected _isFocused
Default value : false
Protected _value
Type : number
Default value : 0
containerClass
Default value : true
Decorators :
@HostBinding('class.cds--form-item')
Static numberCount
Type : number
Default value : 0

Variable used for creating unique ids for number input components.

onTouched
Type : function
Default value : () => {...}

Called when number input is blurred. Needed to properly implement ControlValueAccessor.

propagateChange
Default value : () => {...}

Method set in registerOnChange to propagate changes back to the form.

Accessors

value
getvalue()
setvalue(v: any)

Sets the value attribute on the input element.

Parameters :
Name Type Optional
v any No
Returns : void
decrementLabel
getdecrementLabel()
setdecrementLabel(value: string | Observable)
Parameters :
Name Type Optional
value string | Observable<string> No
Returns : void
incrementLabel
getincrementLabel()
setincrementLabel(value: string | Observable)
Parameters :
Name Type Optional
value string | Observable<string> No
Returns : void
fluidInvalid
getfluidInvalid()
fluidDisabled
getfluidDisabled()
fluidFocus
getfluidFocus()
fluidSkeleton
getfluidSkeleton()
import {
	Component,
	Input,
	HostBinding,
	EventEmitter,
	Output,
	TemplateRef,
	HostListener
} from "@angular/core";
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms";

import { I18n, Overridable } from "carbon-components-angular/i18n";
import { Observable } from "rxjs";

/**
 * Used to emit changes performed on number input components.
 */
export class NumberChange {
	/**
	 * Contains the `Number` that has been changed.
	 */
	source: NumberComponent;
	/**
	 * The value of the `Number` field encompassed in the `NumberChange` class.
	 */
	value: number;
}

/**
 * Get started with importing the module:
 *
 * ```typescript
 * import { NumberModule } from 'carbon-components-angular';
 * ```
 *
 * [See demo](../../?path=/story/components-number--basic)
 */
@Component({
	selector: "cds-number, ibm-number",
	template: `
		<label *ngIf="skeleton && label" class="cds--label cds--skeleton"></label>
		<div
			data-numberinput
			[attr.data-invalid]="(invalid ? true : null)"
			class="cds--number"
			[ngClass]="{
				'cds--number--light': theme === 'light',
				'cds--number--nolabel': hideLabel || !label,
				'cds--number--nosteppers': hideSteppers,
				'cds--number--helpertext': helperText,
				'cds--skeleton' : skeleton,
				'cds--number--sm': size === 'sm',
				'cds--number--md': size === 'md',
				'cds--number--lg': size === 'lg'
			}">
			<label
				*ngIf="!skeleton && label"
				[for]="id"
				class="cds--label"
				[ngClass]="{
					'cds--label--disabled': disabled,
					'cds--visually-hidden': hideLabel
				}">
				<ng-container *ngIf="!isTemplate(label)">{{label}}</ng-container>
				<ng-template *ngIf="isTemplate(label)" [ngTemplateOutlet]="label"></ng-template>
			</label>
			<div
				class="cds--number__input-wrapper"
				[ngClass]="{
					'cds--number__input-wrapper--warning': warn,
					'cds--number__input-wrapper--decorator': !!decorator
				}">
				<input
					type="number"
					[id]="id"
					[value]="value"
					[attr.min]="min"
					[attr.max]="max"
					[attr.step]="step"
					[disabled]="disabled"
					[readonly]="readonly"
					[required]="required"
					[attr.aria-label]="ariaLabel"
					[attr.data-invalid]="invalid ? invalid : null"
					[attr.inputmode]="inputMode || null"
					[attr.pattern]="pattern || null"
					[placeholder]="placeholder"
					(focus)="fluid ? handleFocus($event): null"
					(blur)="fluid ? handleFocus($event): null"
					(change)="onNumberInputChange($event)"/>
				<ng-container *ngIf="decorator">
					<div class="cds--number__input-inner-wrapper--decorator">
						<ng-template [ngTemplateOutlet]="decorator"></ng-template>
					</div>
				</ng-container>
				<svg
					*ngIf="!skeleton && invalid"
					cdsIcon="warning--filled"
					size="16"
					class="cds--number__invalid">
				</svg>
				<svg
					*ngIf="!skeleton && !invalid && warn"
					cdsIcon="warning--alt--filled"
					size="16"
					class="cds--number__invalid cds--number__invalid--warning">
				</svg>
				<div *ngIf="!skeleton && !hideSteppers" class="cds--number__controls">
					<button
						class="cds--number__control-btn down-icon"
						type="button"
						[attr.disabled]="disabled ? true : null"
						aria-live="polite"
						aria-atomic="true"
						[attr.aria-label]="getDecrementLabel() | async"
						(click)="onDecrement()">
						<svg cdsIcon="subtract" size="16"></svg>
					</button>
					<div class="cds--number__rule-divider"></div>
					<button
						class="cds--number__control-btn up-icon"
						type="button"
						[attr.disabled]="disabled ? true : null"
						aria-live="polite"
						aria-atomic="true"
						[attr.aria-label]="getIncrementLabel() | async"
						(click)="onIncrement()">
						<svg cdsIcon="add" size="16"></svg>
					</button>
					<div class="cds--number__rule-divider"></div>
				</div>
			</div>
			<hr *ngIf="fluid" class="cds--number-input__divider" />
			<div
				*ngIf="helperText && !invalid && !warn && !fluid"
				class="cds--form__helper-text"
				[ngClass]="{
					'cds--form__helper-text--disabled': disabled
				}">
				<ng-container *ngIf="!isTemplate(helperText)">{{helperText}}</ng-container>
				<ng-template *ngIf="isTemplate(helperText)" [ngTemplateOutlet]="helperText"></ng-template>
			</div>
			<div *ngIf="invalid" class="cds--form-requirement">
				<ng-container *ngIf="!isTemplate(invalidText)">{{invalidText}}</ng-container>
				<ng-template *ngIf="isTemplate(invalidText)" [ngTemplateOutlet]="invalidText"></ng-template>
			</div>
			<div *ngIf="!invalid && warn" class="cds--form-requirement">
				<ng-container *ngIf="!isTemplate(warnText)">{{warnText}}</ng-container>
				<ng-template *ngIf="isTemplate(warnText)" [ngTemplateOutlet]="warnText"></ng-template>
			</div>
		</div>
	`,
	providers: [
		{
			provide: NG_VALUE_ACCESSOR,
			useExisting: NumberComponent,
			multi: true
		}
	]
})
export class NumberComponent implements ControlValueAccessor {
	/**
	 * Variable used for creating unique ids for number input components.
	 */
	static numberCount = 0;

	@HostBinding("class.cds--form-item") containerClass = true;

	/**
	 * Set to `true` for readonly state.
	 */
	@Input() @HostBinding("class.cds--number--readonly") readonly = false;
	/**
	 * @deprecated since v5 - Use `cdsLayer` directive instead
	 * `light` or `dark` number input theme.
	 */
	@Input() theme: "light" | "dark" = "dark";
	/**
	 * Set to `true` for a disabled number input.
	 */
	@Input() disabled = false;
	/**
	 * Set to `true` for a loading number component.
	 */
	@Input() skeleton = false;
	/**
	 * Set to `true` for an invalid number component.
	 */
	@Input() invalid = false;
	/**
	 * The unique id for the number component.
	 */
	@Input() id = `number-${NumberComponent.numberCount}`;
	/**
	 * Sets the placeholder attribute on the `input` element.
	 */
	@Input() placeholder = "";
	/**
	 * Number input field render size
	 */
	@Input() size: "sm" | "md" | "lg" = "md";
	/**
	 * Reflects the required attribute of the `input` element.
	 */
	@Input() required: boolean;
	/**
	 * Sets the value attribute on the `input` element.
	 */
	@Input() set value(v: any) {
		if (v === "" || v === null) {
			this._value = null;
			return;
		}
		this._value = Number(v);
	}

	get value() {
		return this._value;
	}
	/**
	 * Sets the min attribute on the `input` element.
	 */
	@Input() min = null;
	/**
	 * Sets the max attribute on the `input` element.
	 */
	@Input() max = null;
	/**
	 * Sets the text inside the `label` tag.
	 */
	@Input() label: string | TemplateRef<any>;
	/**
	 * **Experimental**: Optional decorator (e.g. AI label).
	 */
	@Input() decorator: TemplateRef<any>;

	/**
	 * Sets the optional helper text.
	 */
	@Input() helperText: string | TemplateRef<any>;
	/**
	 * Sets the invalid text.
	 */
	@Input() invalidText: string | TemplateRef<any>;
	/**
	 * Sets the amount the number controls increment and decrement by.
	 */
	@Input() step = 1;
	/**
	 * If `step` is a decimal, we may want precision to be set to go around floating point precision.
	 */
	@Input() precision: number;
	/**
	 * Set to `true` to show a warning (contents set by warningText)
	 */
	@Input() warn = false;
	/**
	 * Sets the warning text
	 */
	@Input() warnText: string | TemplateRef<any>;
	/**
	 * Sets the arialabel for input
	 */
	@Input() ariaLabel: string;
	/**
	 * Visually hide the label while keeping it available for screen readers.
	 */
	@Input() hideLabel = false;
	/**
	 * Hide the increment / decrement controls.
	 */
	@Input() hideSteppers = false;
	/**
	 * `inputmode` attribute hint for mobile keyboards.
	 * Instruct the browser which keyboard to display on mobile devices. Defaults
	 * to `decimal`, but note that standard numeric keyboards vary across devices
	 * and operating systems.
	 *
	 * https://css-tricks.com/everything-you-ever-wanted-to-know-about-inputmode/
	 */
	@Input() inputMode = "decimal";
	/**
	 * `pattern` attribute applied to the underlying `<input>`.
	 */
	@Input() pattern: string;
	/**
	 * Emits event notifying other classes when a change in state occurs in the input.
	 */
	@Output() change = new EventEmitter<NumberChange>();

	@Input()
	set decrementLabel(value: string | Observable<string>) {
		this._decrementLabel.override(value);
	}

	get decrementLabel() {
		return this._decrementLabel.value;
	}

	@Input()
	set incrementLabel(value: string | Observable<string>) {
		this._incrementLabel.override(value);
	}

	get incrementLabel() {
		return this._incrementLabel.value;
	}

	/**
	 * Experimental: enable fluid state
	 */
	@HostBinding("class.cds--number-input--fluid") @Input() fluid = false;

	@HostBinding("class.cds--number-input--fluid--invalid") get fluidInvalid() {
		return this.fluid && this.invalid;
	}

	@HostBinding("class.cds--number-input--fluid--disabled") get fluidDisabled() {
		return this.fluid && this.disabled;
	}

	@HostBinding("class.cds--number-input--fluid--focus") get fluidFocus() {
		return this.fluid && this._isFocused;
	}

	@HostBinding("class.cds--text-input--fluid__skeleton") get fluidSkeleton() {
		return this.fluid && this.skeleton;
	}

	protected _isFocused = false;

	protected _value = 0;

	protected _decrementLabel: Overridable = this.i18n.getOverridable("NUMBER.DECREMENT");
	protected _incrementLabel: Overridable = this.i18n.getOverridable("NUMBER.INCREMENT");

	/**
	 * Creates an instance of `Number`.
	 */
	constructor(protected i18n: I18n) {
		NumberComponent.numberCount++;
	}

	/**
	 * This is the initial value set to the component
	 * @param value The input value.
	 */
	public writeValue(value: any) {
		this.value = value;
	}

	/**
	 * Sets a method in order to propagate changes back to the form.
	 */
	public registerOnChange(fn: any) {
		this.propagateChange = fn;
	}

	/**
	 * Registers a callback to be triggered when the control has been touched.
	 * @param fn Callback to be triggered when the number input is touched.
	 */
	public registerOnTouched(fn: any) {
		this.onTouched = fn;
	}

	@HostListener("focusout")
	focusOut() {
		this.onTouched();
	}

	/**
	 * Sets the disabled state through the model
	 */
	setDisabledState(isDisabled: boolean) {
		this.disabled = isDisabled;
	}

	/**
	 * Called when number input is blurred. Needed to properly implement `ControlValueAccessor`.
	 */
	onTouched: () => any = () => { };

	/**
	 * Method set in `registerOnChange` to propagate changes back to the form.
	 */
	propagateChange = (_: any) => { };

	/**
	 * Adds `step` to the current `value`.
	 */
	onIncrement(): void {
		// if max is set and value + step is greater than max, set value to max
		// example: max = 100, step = 10, value = 95 , value + step = 105, value will be set to 100 (max) instead of 105
		if (this.max !== null && this.value + this.step > this.max) {
			this.value = this.max;
			this.emitChangeEvent();
			return;
		}

		// if min is set and value + step is less than min, set value to min
		// example: min = 5, step = 2, value = 0, value + step = 2, value will be set to 5 (min) instead of 2
		if (this.min !== null && this.value + this.step < this.min) {
			this.value = this.min;
			this.emitChangeEvent();
			return;
		}

		// if max is not set or value + step is less than max, increment value by step
		if (this.max === null || this.value + this.step <= this.max) {
			this.value += this.step;
			this.value = parseFloat(this.value.toPrecision(this.precision));
			this.emitChangeEvent();
		}
	}

	/**
	 * Subtracts `step` to the current `value`.
	 */
	onDecrement(): void {
		// if max is set and value - step is greater than max, set value to max
		// example: max = 15, step = 2, value = 20, value - step = 18, value will be set to 15 (max) instead of 18
		if (this.max !== null && this.value - this.step > this.max) {
			this.value = this.max;
			this.emitChangeEvent();
			return;
		}

		// if min is set and value - step is less than min, set value to min
		// example: min = 5, step = 2, value = 6, value - step = 4, value will be set to 5 (min) instead of 4
		if (this.min !== null && this.value - this.step < this.min) {
			this.value = this.min;
			this.emitChangeEvent();
			return;
		}

		// if min is not set or value - step is greater than min, decrement value by step
		if (this.min === null || this.value - this.step >= this.min) {
			this.value -= this.step;
			this.value = parseFloat(this.value.toPrecision(this.precision));
			this.emitChangeEvent();
		}
	}

	getDecrementLabel(): Observable<string> {
		return this._decrementLabel.subject;
	}

	getIncrementLabel(): Observable<string> {
		return this._incrementLabel.subject;
	}

	/**
	 * Creates a class of `NumberChange` to emit the change in the `Number`.
	 */
	emitChangeEvent(): void {
		let event = new NumberChange();
		event.source = this;
		event.value = this.value;
		this.change.emit(event);
		this.propagateChange(this.value);
	}

	onNumberInputChange(event) {
		this.value = event.target.value;
		this.emitChangeEvent();
	}

	public isTemplate(value) {
		return value instanceof TemplateRef;
	}

	handleFocus(event: FocusEvent) {
		if ("type" in event.target && (<HTMLInputElement>event.target).type === "button") {
			this._isFocused = false;
		} else {
			this._isFocused = event.type === "focus";
		}
	}
}
export { NumberComponent as Number };
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""