di-controls
Version:
<!-- PROJECT LOGO -->
239 lines (238 loc) • 8.18 kB
TypeScript
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>;
}