UNPKG

di-controls

Version:
239 lines (238 loc) 8.18 kB
import { OnInit } from '@angular/core'; import { DIControlValueAccessor, DIControlValueAccessorConfig } from './control-value-accessor'; import * as i0 from "@angular/core"; /** * Configuration for the `DIControl`. */ export interface DIControlConfig<TModel, TChildModel> extends DIControlValueAccessorConfig<TModel> { /** * Host control for the current control. It can be injected using `DI_HOST_CONTROL` token. */ host?: DIControl<any, TModel> | null; /** * Function that will be called when the current control receives an update from the child control. * * @param control - child control that was updated. * @param value - new value. */ onChildControlChange?: (control: DIControl<TChildModel>, value: TModel | null) => void; } /** * `DIControl` can be used to implement any control that you want. It can work with any model type. * All updates from children will be accepted as is. And updates from outside (`FormControl`, `NgModel`, another Control) * will be accepted as is too. * * ## Creating a control * To create a control you need to extend your `@Component` or `@Directive` from `DIControl` class. * After that your control will be able to work with `NgModel`, `FormControl`. * * ```ts fileName="custom-control.component.ts" * @Component({}) * export class CustomControlComponent extends DIControl<string> { * constructor() { * super(); * } * } * ``` * * ## Registering as a host * By default your control can work only with `NgModel` and `FormControl`. But you can register your control as a host * for another controls, then your control will be able to update them and accept updates from them. To do that you need to * use `provideHostControl` function. * * ```ts {2} fileName="custom-control.component.ts" * @Component({ * providers: [provideHostControl(CustomControlComponent)], * }) * export class CustomControlComponent extends DIControl<string> { * constructor() { * super(); * } * } * ``` * * ## Injecting host control * By default your control doesn't communicate with host controls. But you can inject host control and put it * into `super` call. This will register your control in the host control and start communication between them. * * > **Note** * > If you register your control as a host for another controls, then you can inject it * > only with `skipSelf` option. * * ```ts {5} fileName="custom-control.component.ts" * @Component({}) * export class CustomControlComponent extends DIControl<string> { * constructor() { * // we add `optional` option to make it possible to use this control without host * super({host: injectHostControl({optional: true})}); * } * } * ``` * * ## Getting model * To get model you need to use `model` property. It will return model for the current control. * * ```ts {9} fileName="custom-control.component.ts" * @Component({}) * export class CustomControlComponent extends DIControl<string> { * constructor() { * super(); * } * * @HostListener('click') * onClick() { * console.log(this.model()); * } * } * ``` * * ## Updating model * To update model you need to call `updateModel` method. It will update model for the current control and all * children controls, as well as for the `NgModel` or `FormControl`. * * ```ts {9} fileName="custom-control.component.ts" * @Component({}) * export class CustomControlComponent extends DIControl<string> { * constructor() { * super(); * } * * @HostListener('click') * onClick() { * this.updateModel('new value'); * } * } * ``` * ## Catching updates * Sometimes you may need to catch updates from different sources. For example, to update the value of the native * input element. To do this, you can provide the `onIncomingUpdate` hook. * * ```ts {6} fileName="custom-control.component.ts" * @Component({}) * export class CustomControlComponent extends DIControl<string> { * constructor() { * super({ * onIncomingUpdate: (value: string | null) => { * this.elementRef.nativeElement.value = value; * }, * }); * } * } * ``` */ export declare abstract class DIControl<TModel, TChildModel = TModel> extends DIControlValueAccessor<TModel> implements OnInit { protected readonly config?: DIControlConfig<TModel, TChildModel> | undefined; /** * List of children controls. * * @protected * @internal */ protected children: Set<DIControl<TChildModel>>; /** * Control from which we have to update our model. * * @protected * @internal */ protected updateFrom: DIControl<TChildModel> | null; /** * Request host for update the current control. * Host will update the current control based on its current state and host control logic. * * @protected * @internal */ protected requestForUpdate: () => void; /** * Function that should be used to make control touched. */ protected touch: () => void; private onControlChangeFn; private destroyRef; protected constructor(config?: DIControlConfig<TModel, TChildModel> | undefined); ngOnInit(): void; /** * Registers provided control as a child of the current control. * * @param control - control that will be registered. * @internal */ registerControl(control: DIControl<TChildModel>): void; /** * Unregisters provided control from the current control. * * @param control - control that will be unregistered. * @internal */ unregisterControl(control: DIControl<TChildModel>): void; registerOnTouched(fn: () => void): void; /** * Registers provided function as a callback that will be called when the current control changes. * This function will be provided by the host control to update its model. * * @param fn - callback function. * @internal */ registerOnControlChange(fn: (value: TModel | null) => void): void; /** * Registers provided function as a callback that can be called to request an update from the host control. * After calling this function the host control will update the model of the current control based on the current * state of the control and host control logic. * * @param fn - callback function. * @internal */ registerRequestForUpdate(fn: () => void): void; /** * Updates the model of the current control. * This is the main method that should be used to update the model. * * @param value - new value. */ updateModel(value: TModel | null): void; /** * Updates the model of the current control. * Don't use this method directly, use `updateModel` instead. * * @param value - new value. * @internal */ internalUpdateModel(value: TModel | null): void; writeValue(value: TModel | null): void; /** * Method is called by the host to update the value of the control. * * @param value - new value * @internal */ writeValueFromHost(value: TModel | null): void; /** * Updates all child controls with the provided value. * * @param value - new value. * @protected * @internal */ protected updateControls(value: TModel | null): void; /** * Updates provided control with the provided value. * * @param control - control that will be updated. * @param value - new value. * @protected * @internal */ protected updateControl(control: DIControl<TChildModel>, value: TModel | null): void; /** * Function catches updates from child controls and updates the current control model. * * @param control - control that was updated. * @param value - new value. * @protected * @internal */ protected childControlChange(control: DIControl<TChildModel>, value: TModel | null): void; static ɵfac: i0.ɵɵFactoryDeclaration<DIControl<any, any>, never>; static ɵdir: i0.ɵɵDirectiveDeclaration<DIControl<any, any>, never, never, {}, {}, never, never, true, never>; }