@rytrox/form-signals
Version:
Simple Reimplementation of [Angular Forms](https://www.npmjs.com/package/@angular/forms) in Signals. Focused on simplicity, with full [Angular Material](https://www.npmjs.com/package/@angular/material) support.
1,060 lines (1,034 loc) • 45.8 kB
JavaScript
import * as i0 from '@angular/core';
import { signal, isSignal, computed, input, inject, ElementRef, effect, HostListener, Directive, booleanAttribute, forwardRef, NgModule } from '@angular/core';
import { isFunction } from 'lodash';
import { CommonModule } from '@angular/common';
import { MatCheckbox } from '@angular/material/checkbox';
import { MatRadioGroup } from '@angular/material/radio';
import { MatSliderThumb, MatSliderRangeThumb } from '@angular/material/slider';
import { MatSlideToggle } from '@angular/material/slide-toggle';
import { MatSelect } from '@angular/material/select';
import { MatButtonToggleGroup } from '@angular/material/button-toggle';
import { MatDatepickerInput } from '@angular/material/datepicker';
import { Subscription } from 'rxjs';
const createAbstractForm = (getter) => {
const form = getter;
const _validators = signal([]);
Object.defineProperty(form, "validators", {
value: _validators,
writable: false
});
Object.defineProperty(form, "addValidators", {
value: (...validators) => {
const set = new Set(_validators());
validators.forEach(validator => set.add(validator));
_validators.set([...set]);
}
});
Object.defineProperty(form, "removeValidators", {
value: (...validators) => {
const set = new Set(_validators());
validators.forEach(validator => set.delete(validator));
_validators.set([...set]);
}
});
Object.defineProperty(form, "hasValidator", {
value: (validator) => {
const set = new Set(_validators());
return set.has(validator);
}
});
return form;
};
const isFormControl = (val) => {
return isSignal(val) &&
'errors' in val && isSignal(val.errors) &&
'validators' in val && isSignal(val.validators) &&
'disabled' in val && isSignal(val.disabled);
};
const isSimpleFormOptions = (val) => {
return !!val && typeof val === 'object' &&
'value' in val &&
(!('disabled' in val) || typeof val.disabled === 'boolean') &&
(!('validators' in val) || Array.isArray(val.validators));
};
function formControl(val) {
if (isSimpleFormOptions(val)) {
return createSimpleForm(val);
}
else {
return createSimpleForm({
value: val,
disabled: false,
validators: [],
});
}
}
const createSimpleForm = (options) => {
const form = createAbstractForm(signal(options.value));
if (options.validators) {
form.addValidators(...options.validators);
}
Object.defineProperty(form, 'errors', {
value: computed(() => {
const validators = form.validators();
const value = form();
const errors = [...validators].map(validator => validator(value))
.filter((error) => !!error);
return errors.length > 0 ?
errors.reduce((error, current) => Object.assign(error, current), {}) :
null;
})
});
Object.defineProperty(form, 'disabled', {
value: signal(!!options.disabled)
});
return form;
};
const formArrayFactory = (fn) => {
return val => {
const controls = signal(val.map(element => fn(element)));
const form = createAbstractForm(computed(() => calcValue$1(controls())));
reindexArray(form, controls());
Object.defineProperty(form, 'length', {
get() {
return controls().length;
}
});
Object.defineProperty(form, 'push', {
value: (value) => {
const control = fn(value);
controls.update(c => [...c, control]);
reindexArray(form, controls());
}
});
Object.defineProperty(form, 'removeAt', {
value: (index) => {
controls.update(controls => controls.filter((_control, i) => i !== index));
reindexArray(form, controls());
}
});
Object.defineProperty(form, 'pop', {
value: () => {
controls.update(c => {
c.pop();
return [...c];
});
Object.defineProperty(form, controls().length, {
value: undefined,
configurable: true
});
}
});
Object.defineProperty(form, Symbol.iterator, {
get() {
return controls()[Symbol.iterator];
}
});
Object.defineProperty(form, 'errors', {
value: computed(() => {
// construct Error object
const groupErrors = calcGroupErrors$1(form(), form.validators());
const controlErrors = calcControlErrors$1(controls());
if (groupErrors === null && Object.keys(controlErrors).length === 0) {
return null;
}
return {
this: groupErrors,
controls: controlErrors
};
})
});
Object.defineProperty(form, 'set', {
value: (array) => {
const properties = Object.fromEntries(controls().map((_control, index) => {
return [index, {
value: undefined,
configurable: true
}];
}));
controls.set(array.map(element => fn(element)));
Object.assign(properties, Object.fromEntries(controls().map((control, index) => {
return [index, {
value: control,
configurable: true
}];
})));
Object.defineProperties(form, properties);
}
});
Object.defineProperty(form, 'update', {
value: (fn) => {
form.set(fn(form()));
}
});
Object.defineProperty(form, 'disable', {
value: () => {
controls().forEach(control => {
if (isFormControl(control)) {
control.disabled.set(true);
}
else if ('disable' in control && isFunction(control.disable)) {
control.disable();
}
});
}
});
Object.defineProperty(form, 'enable', {
value: () => {
controls().forEach(control => {
if (isFormControl(control)) {
control.disabled.set(false);
}
else if ('enable' in control && isFunction(control.enable)) {
control.enable();
}
});
}
});
Object.defineProperty(form, 'map', {
value: (callbackFn) => {
return controls().map(callbackFn);
}
});
Object.defineProperty(form, 'forEach', {
value: (callbackFn) => {
controls().forEach(callbackFn);
}
});
return form;
};
};
const calcValue$1 = (controls) => {
return controls.map(control => control());
};
const reindexArray = (form, controls) => {
Object.defineProperties(form, Object.fromEntries(controls.map((control, index) => {
return [index, {
value: control,
configurable: true
}];
})));
};
const calcGroupErrors$1 = (value, validators) => {
const errors = validators.map(validator => validator(value))
.filter((error) => !!error);
if (errors.length === 0) {
return null;
}
return errors.reduce((error, current) => Object.assign(error, current), {});
};
const calcControlErrors$1 = (controls) => {
return controls.map(control => control.errors());
};
const forbiddenNames = [
'addValidators',
'removeValidators',
'setControl',
'hasValidator',
'errors',
'validators',
];
const formGroupFactory = (fn) => {
return (val) => {
const controls = signal(fn(val));
const form = createAbstractForm(computed(() => calcValue(controls())));
// Register Controls
Object.entries(controls())
.filter((arr) => !!arr[1])
.forEach(([k, v]) => {
if (!forbiddenNames.includes(k)) {
Object.defineProperty(form, k, {
value: v,
configurable: true
});
}
else {
throw new Error(`It is not allowed to name a property "${k}" inside a FormGroup. Please rename it`);
}
});
Object.defineProperty(form, 'errors', {
value: computed(() => {
// construct Error object
const groupErrors = calcGroupErrors(form(), form.validators());
const controlErrors = calcControlErrors(controls());
if (groupErrors === null && Object.keys(controlErrors).length === 0) {
return null;
}
return {
this: groupErrors,
controls: controlErrors
};
})
});
Object.defineProperty(form, 'set', {
value: (val) => {
Object.entries(controls())
.filter((arr) => !!arr[1])
.forEach(([key, control]) => {
control.set(val[key]);
});
}
});
Object.defineProperty(form, 'update', {
value: (fn) => {
form.set(fn(form()));
}
});
Object.defineProperty(form, 'setControl', {
value: (key, control) => {
if (control) {
controls.update(c => {
const newControls = { ...c };
newControls[key] = control;
return newControls;
});
Object.defineProperty(form, key, { value: control, configurable: true });
}
else {
controls.update(c => {
const newControls = { ...c };
delete newControls[key];
return newControls;
});
Object.defineProperty(form, key, { value: undefined, configurable: true });
}
}
});
Object.defineProperty(form, 'disable', {
value: () => {
Object.values(controls())
.filter((control) => !!control)
.forEach(control => {
if (isFormControl(control)) {
control.disabled.set(true);
}
else if ('disable' in control && isFunction(control.disable)) {
control.disable();
}
});
}
});
Object.defineProperty(form, 'enable', {
value: () => {
Object.values(controls())
.filter((control) => !!control)
.forEach(control => {
if (isFormControl(control)) {
control.disabled.set(false);
}
else if ('disable' in control && isFunction(control.disable)) {
control.disable();
}
});
}
});
return form;
};
};
const calcValue = (controls) => {
return Object.fromEntries(Object.entries(controls)
.filter((arr) => !!arr[1])
.map(([key, val]) => [key, val()]));
};
const calcGroupErrors = (value, validators) => {
const errors = validators.map(validator => validator(value))
.filter((error) => !!error);
if (errors.length === 0) {
return null;
}
return errors.reduce((error, current) => Object.assign(error, current), {});
};
const calcControlErrors = (controls) => {
return Object.fromEntries(Object.entries(controls)
.filter((arr) => !!arr[1])
.map(([key, val]) => [key, val.errors()])
.filter(([_key, val]) => !!val));
};
class AbstractFormDirective {
updateValue(form, value) {
form.set(value);
}
}
class InputTextDirective extends AbstractFormDirective {
form = input();
element = inject(ElementRef);
constructor() {
super();
// Update input when form value is updated
effect(() => {
const form = this.form();
if (form) {
this.element.nativeElement.value = form();
this.element.nativeElement.disabled = form.disabled();
}
});
}
onInput() {
const form = this.form();
if (form) {
this.updateValue(form, this.element.nativeElement.value);
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: InputTextDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.3", type: InputTextDirective, isStandalone: false, selector: "textarea[form], input:not([matDatepicker]):not([matSliderThumb]):not([matSliderStartThumb]):not([matSliderEndThumb]):not([type=number]):not([type=checkbox]):not([type=date]):not([type=datetime-local]):not([type=time]):not([type=radio]):not([type=range]):not([type=file])[form]", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "input": "onInput()" } }, usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: InputTextDirective, decorators: [{
type: Directive,
args: [{
selector: 'textarea[form], input:not([matDatepicker]):not([matSliderThumb]):not([matSliderStartThumb]):not([matSliderEndThumb]):not([type=number]):not([type=checkbox]):not([type=date]):not([type=datetime-local]):not([type=time]):not([type=radio]):not([type=range]):not([type=file])[form]',
standalone: false
}]
}], ctorParameters: () => [], propDecorators: { onInput: [{
type: HostListener,
args: ['input']
}] } });
class InputNumberDirective extends AbstractFormDirective {
form = input();
element = inject(ElementRef);
constructor() {
super();
// Update input when form value is updated
effect(() => {
const form = this.form();
if (form) {
this.element.nativeElement.valueAsNumber = form();
this.element.nativeElement.disabled = form.disabled();
}
});
}
/**
* Blocks incoming input that are not numbers
*
* @param event
*/
onKeyDown(event) {
if (event.key.length === 1 && !/[-+.0-9]/.test(event.key)) {
event.preventDefault();
}
}
onInput() {
const form = this.form();
if (form) {
this.updateValue(form, this.element.nativeElement.valueAsNumber);
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: InputNumberDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.3", type: InputNumberDirective, isStandalone: false, selector: "input[type=number][form]", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "keydown": "onKeyDown($event)", "input": "onInput()" } }, usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: InputNumberDirective, decorators: [{
type: Directive,
args: [{
selector: 'input[type=number][form]',
standalone: false
}]
}], ctorParameters: () => [], propDecorators: { onKeyDown: [{
type: HostListener,
args: ['keydown', ['$event']]
}], onInput: [{
type: HostListener,
args: ['input']
}] } });
class MatCheckboxDirective extends AbstractFormDirective {
form = input();
element = inject(MatCheckbox, { self: true });
constructor() {
super();
// Update input when form value is updated
effect(() => {
const form = this.form();
if (form) {
this.element.writeValue(form());
this.element.setDisabledState(form.disabled());
}
});
}
onValueChange() {
const form = this.form();
if (form) {
this.updateValue(form, this.element.checked);
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: MatCheckboxDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.3", type: MatCheckboxDirective, isStandalone: false, selector: "mat-checkbox[form]", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "input": "onValueChange()" } }, usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: MatCheckboxDirective, decorators: [{
type: Directive,
args: [{
selector: 'mat-checkbox[form]',
standalone: false
}]
}], ctorParameters: () => [], propDecorators: { onValueChange: [{
type: HostListener,
args: ['input']
}] } });
class InputCheckboxDirective extends AbstractFormDirective {
form = input();
element = inject(ElementRef);
constructor() {
super();
effect(() => {
const form = this.form();
if (form) {
this.element.nativeElement.checked = form();
this.element.nativeElement.disabled = form.disabled();
}
});
}
onChange() {
const form = this.form();
if (form) {
this.updateValue(form, this.element.nativeElement.checked);
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: InputCheckboxDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.3", type: InputCheckboxDirective, isStandalone: false, selector: "input[type=checkbox][form]", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "input": "onChange()" } }, usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: InputCheckboxDirective, decorators: [{
type: Directive,
args: [{
selector: 'input[type=checkbox][form]',
standalone: false
}]
}], ctorParameters: () => [], propDecorators: { onChange: [{
type: HostListener,
args: ['input']
}] } });
class InputDateDirective extends AbstractFormDirective {
form = input();
element = inject(ElementRef);
constructor() {
super();
effect(() => {
const form = this.form();
if (form) {
this.element.nativeElement.valueAsDate = form();
this.element.nativeElement.disabled = form.disabled();
}
});
}
onInput() {
const form = this.form();
if (form) {
super.updateValue(form, this.element.nativeElement.valueAsDate);
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: InputDateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.3", type: InputDateDirective, isStandalone: false, selector: "input[type=date][form], input[type=datetime-local][form], input[type=time][form]", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "input": "onInput()" } }, usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: InputDateDirective, decorators: [{
type: Directive,
args: [{
selector: 'input[type=date][form], input[type=datetime-local][form], input[type=time][form]',
standalone: false
}]
}], ctorParameters: () => [], propDecorators: { onInput: [{
type: HostListener,
args: ['input']
}] } });
class InputRadioDirective extends AbstractFormDirective {
form = input();
element = inject(ElementRef);
constructor() {
super();
effect(() => {
const form = this.form();
if (form) {
this.element.nativeElement.checked = form() === this.element.nativeElement.value;
this.element.nativeElement.disabled = form.disabled();
}
});
}
onClick() {
const form = this.form();
if (form) {
const checked = this.element.nativeElement.checked;
if (checked) {
this.updateValue(form, this.element.nativeElement.value);
}
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: InputRadioDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.3", type: InputRadioDirective, isStandalone: false, selector: "input[type=radio][form]", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "change": "onClick()" } }, usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: InputRadioDirective, decorators: [{
type: Directive,
args: [{
selector: 'input[type=radio][form]',
standalone: false
}]
}], ctorParameters: () => [], propDecorators: { onClick: [{
type: HostListener,
args: ['change']
}] } });
class MatRadioGroupDirective extends AbstractFormDirective {
form = input();
element = inject(MatRadioGroup);
constructor() {
super();
effect(() => {
const form = this.form();
if (form) {
this.element.writeValue(form());
this.element.setDisabledState(form.disabled());
}
});
}
onValueChange(event) {
const form = this.form();
if (form) {
this.updateValue(form, event.value);
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: MatRadioGroupDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.3", type: MatRadioGroupDirective, isStandalone: false, selector: "mat-radio-group[form]", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "change": "onValueChange($event)" } }, usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: MatRadioGroupDirective, decorators: [{
type: Directive,
args: [{
selector: 'mat-radio-group[form]',
standalone: false
}]
}], ctorParameters: () => [], propDecorators: { onValueChange: [{
type: HostListener,
args: ['change', ['$event']]
}] } });
class InputRangeDirective extends AbstractFormDirective {
form = input();
element = inject(ElementRef);
constructor() {
super();
effect(() => {
const form = this.form();
if (form) {
this.element.nativeElement.valueAsNumber = form();
this.element.nativeElement.disabled = form.disabled();
}
});
}
onInput() {
const form = this.form();
if (form) {
this.updateValue(form, this.element.nativeElement.valueAsNumber);
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: InputRangeDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.3", type: InputRangeDirective, isStandalone: false, selector: "input[type=range][form]", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "input": "onInput()" } }, usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: InputRangeDirective, decorators: [{
type: Directive,
args: [{
selector: 'input[type=range][form]',
standalone: false
}]
}], ctorParameters: () => [], propDecorators: { onInput: [{
type: HostListener,
args: ['input']
}] } });
class InputFileDirective extends AbstractFormDirective {
multiple = input(false, { transform: booleanAttribute });
form = input();
element = inject(ElementRef);
constructor() {
super();
effect(() => {
const form = this.form();
if (form) {
const val = form();
if (val) {
const list = new DataTransfer();
if (Array.isArray(val)) {
val.forEach(item => list.items.add(item));
}
else {
list.items.add(val);
}
this.element.nativeElement.files = list.files;
}
else {
this.element.nativeElement.files = null;
}
this.element.nativeElement.disabled = form.disabled();
}
});
}
onFileChange() {
const form = this.form();
if (form) {
if (this.element.nativeElement.files) {
const file = this.element.nativeElement.files;
if (this.isFileArrayForm(form)) {
const arr = [];
for (let i = 0; i < file.length; i++) {
const item = file.item(i);
if (item) {
arr.push(item);
}
}
form.set(arr);
}
else {
form.set(file.item(0));
}
}
else {
form.set(null);
}
}
}
isFileArrayForm(_val) {
return this.multiple();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: InputFileDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.3", type: InputFileDirective, isStandalone: false, selector: "input[multiple][type=file][form], input[type=\"file\"][form]", inputs: { multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "input": "onFileChange()" } }, usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: InputFileDirective, decorators: [{
type: Directive,
args: [{
selector: 'input[multiple][type=file][form], input[type="file"][form]',
standalone: false
}]
}], ctorParameters: () => [], propDecorators: { onFileChange: [{
type: HostListener,
args: ['input']
}] } });
class SelectDirective extends AbstractFormDirective {
form = input();
element = inject(ElementRef);
constructor() {
super();
effect(() => {
const form = this.form();
if (form) {
this.element.nativeElement.value = form();
this.element.nativeElement.disabled = form.disabled();
}
});
}
onChange() {
const form = this.form();
if (form) {
this.updateValue(form, this.element.nativeElement.value);
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: SelectDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.3", type: SelectDirective, isStandalone: false, selector: "select[form]", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "change": "onChange()" } }, usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: SelectDirective, decorators: [{
type: Directive,
args: [{
selector: 'select[form]',
standalone: false
}]
}], ctorParameters: () => [], propDecorators: { onChange: [{
type: HostListener,
args: ['change']
}] } });
class MatSliderThumbDirective extends MatSliderThumb {
form = input();
constructor() {
super();
effect(() => {
const form = this.form();
if (form) {
this.writeValue(form());
this.setDisabledState(form.disabled());
}
});
}
onInput() {
const form = this.form();
if (form) {
form.set(this.value);
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: MatSliderThumbDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.3", type: MatSliderThumbDirective, isStandalone: false, selector: "input[matSliderThumb][form]", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "input": "onInput()" } }, providers: [
{
provide: MatSliderThumb,
useExisting: forwardRef(() => MatSliderThumbDirective),
}
], usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: MatSliderThumbDirective, decorators: [{
type: Directive,
args: [{
selector: 'input[matSliderThumb][form]',
providers: [
{
provide: MatSliderThumb,
useExisting: forwardRef(() => MatSliderThumbDirective),
}
],
standalone: false
}]
}], ctorParameters: () => [], propDecorators: { onInput: [{
type: HostListener,
args: ['input']
}] } });
class MatSlideToggleDirective extends AbstractFormDirective {
form = input();
element = inject(MatSlideToggle);
constructor() {
super();
effect(() => {
const form = this.form();
if (form) {
this.element.writeValue(form());
this.element.setDisabledState(form.disabled());
}
});
}
onChange() {
const form = this.form();
if (form) {
this.updateValue(form, this.element.checked);
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: MatSlideToggleDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.3", type: MatSlideToggleDirective, isStandalone: false, selector: "mat-slide-toggle[form]", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "change": "onChange()" } }, usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: MatSlideToggleDirective, decorators: [{
type: Directive,
args: [{
selector: 'mat-slide-toggle[form]',
standalone: false
}]
}], ctorParameters: () => [], propDecorators: { onChange: [{
type: HostListener,
args: ['change']
}] } });
class MatSelectDirective extends AbstractFormDirective {
form = input();
element = inject(MatSelect);
constructor() {
super();
effect(() => {
const form = this.form();
if (form) {
this.element.writeValue(form());
this.element.setDisabledState(form.disabled());
}
});
}
onChange(event) {
const form = this.form();
if (form) {
if (this.isArrayForm(form)) {
const arr = Array.isArray(event.value) ? event.value : [event.value];
form.set(arr);
}
else {
form.set(event.value);
}
}
}
isArrayForm(_form) {
return this.element.multiple;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: MatSelectDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.3", type: MatSelectDirective, isStandalone: false, selector: "mat-select[form]", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "selectionChange": "onChange($event)" } }, usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: MatSelectDirective, decorators: [{
type: Directive,
args: [{
selector: 'mat-select[form]',
standalone: false
}]
}], ctorParameters: () => [], propDecorators: { onChange: [{
type: HostListener,
args: ['selectionChange', ['$event']]
}] } });
class MatButtonToggleGroupDirective extends AbstractFormDirective {
form = input();
element = inject(MatButtonToggleGroup);
constructor() {
super();
effect(() => {
const form = this.form();
if (form) {
this.element.writeValue(form());
this.element.setDisabledState(form.disabled());
}
});
}
onChange(event) {
const form = this.form();
if (form) {
form.set(event.value);
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: MatButtonToggleGroupDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.3", type: MatButtonToggleGroupDirective, isStandalone: false, selector: "mat-button-toggle-group[form]", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "change": "onChange($event)" } }, usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: MatButtonToggleGroupDirective, decorators: [{
type: Directive,
args: [{
selector: 'mat-button-toggle-group[form]',
standalone: false
}]
}], ctorParameters: () => [], propDecorators: { onChange: [{
type: HostListener,
args: ['change', ['$event']]
}] } });
class MatSliderRangeThumbDirective extends MatSliderRangeThumb {
form = input();
constructor() {
super();
effect(() => {
const form = this.form();
if (form) {
this.writeValue(form());
this.setDisabledState(form.disabled());
}
});
}
onInput() {
const form = this.form();
if (form) {
form.set(this.value);
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: MatSliderRangeThumbDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.3", type: MatSliderRangeThumbDirective, isStandalone: false, selector: "input[matSliderStartThumb][form], input[matSliderEndThumb][form]", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "input": "onInput()" } }, providers: [
{
provide: MatSliderRangeThumb,
useExisting: forwardRef(() => MatSliderRangeThumbDirective),
}
], usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: MatSliderRangeThumbDirective, decorators: [{
type: Directive,
args: [{
selector: 'input[matSliderStartThumb][form], input[matSliderEndThumb][form]',
providers: [
{
provide: MatSliderRangeThumb,
useExisting: forwardRef(() => MatSliderRangeThumbDirective),
}
],
standalone: false
}]
}], ctorParameters: () => [], propDecorators: { onInput: [{
type: HostListener,
args: ['input']
}] } });
class MatDatepickerDirective extends AbstractFormDirective {
form = input();
datePicker = inject(MatDatepickerInput);
subscription = new Subscription();
constructor() {
super();
effect(() => {
const form = this.form();
if (form) {
this.datePicker.writeValue(form());
this.datePicker.setDisabledState(form.disabled());
}
});
this.subscription.add(this.datePicker.dateChange.subscribe(date => {
const form = this.form();
if (form) {
this.updateValue(form, date.value);
}
}));
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: MatDatepickerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.3", type: MatDatepickerDirective, isStandalone: false, selector: "input[matDatepicker][form]", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: MatDatepickerDirective, decorators: [{
type: Directive,
args: [{
selector: 'input[matDatepicker][form]',
standalone: false
}]
}], ctorParameters: () => [] });
class FormsModule {
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: FormsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.0.3", ngImport: i0, type: FormsModule, declarations: [InputCheckboxDirective,
InputDateDirective,
InputFileDirective,
InputNumberDirective,
InputRadioDirective,
InputRangeDirective,
InputTextDirective,
SelectDirective,
MatButtonToggleGroupDirective,
MatCheckboxDirective,
MatDatepickerDirective,
MatRadioGroupDirective,
MatSelectDirective,
MatSlideToggleDirective,
MatSliderRangeThumbDirective,
MatSliderThumbDirective], imports: [CommonModule], exports: [InputCheckboxDirective,
InputDateDirective,
InputFileDirective,
InputNumberDirective,
InputRadioDirective,
InputRangeDirective,
InputTextDirective,
SelectDirective,
MatButtonToggleGroupDirective,
MatCheckboxDirective,
MatDatepickerDirective,
MatRadioGroupDirective,
MatSelectDirective,
MatSlideToggleDirective,
MatSliderRangeThumbDirective,
MatSliderThumbDirective] });
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: FormsModule, imports: [CommonModule] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: FormsModule, decorators: [{
type: NgModule,
args: [{
declarations: [
InputCheckboxDirective,
InputDateDirective,
InputFileDirective,
InputNumberDirective,
InputRadioDirective,
InputRangeDirective,
InputTextDirective,
SelectDirective,
MatButtonToggleGroupDirective,
MatCheckboxDirective,
MatDatepickerDirective,
MatRadioGroupDirective,
MatSelectDirective,
MatSlideToggleDirective,
MatSliderRangeThumbDirective,
MatSliderThumbDirective
],
imports: [
CommonModule,
],
exports: [
InputCheckboxDirective,
InputDateDirective,
InputFileDirective,
InputNumberDirective,
InputRadioDirective,
InputRangeDirective,
InputTextDirective,
SelectDirective,
MatButtonToggleGroupDirective,
MatCheckboxDirective,
MatDatepickerDirective,
MatRadioGroupDirective,
MatSelectDirective,
MatSlideToggleDirective,
MatSliderRangeThumbDirective,
MatSliderThumbDirective
]
}]
}] });
/*
* Public API Surface of form-signals
*/
/**
* Generated bundle index. Do not edit.
*/
export { AbstractFormDirective, FormsModule, InputCheckboxDirective, InputDateDirective, InputFileDirective, InputNumberDirective, InputRadioDirective, InputRangeDirective, InputTextDirective, MatButtonToggleGroupDirective, MatCheckboxDirective, MatDatepickerDirective, MatRadioGroupDirective, MatSelectDirective, MatSlideToggleDirective, MatSliderRangeThumbDirective, MatSliderThumbDirective, SelectDirective, formArrayFactory, formControl, formGroupFactory, isFormControl };
//# sourceMappingURL=rytrox-form-signals.mjs.map