### File

`src/lib/directives/control-hide-show.directive.ts`

### Index

###### Properties
Optional rootChange

### Properties

rootChange
`rootChange: `boolean``
Type : `boolean`
Optional
Weather the hide/showFunction should be called on root group changes

    import {
      Directive,
      ElementRef,
      Inject,
      Input,
      OnDestroy,
      OnInit,
      Optional,
      Renderer2,
      Self,
    } from '@angular/core';
    import {
      AbstractControl,
      FormDefinition,
      RxapFormControl,
    } from '@rxap/forms';
    import {
      ControlContainer,
      NgControl,
    } from '@angular/forms';
    import { Mixin } from '@rxap/mixin';
    import {
      of,
      Subscription,
    } from 'rxjs';
    import {
      catchError,
      startWith,
      tap,
    } from 'rxjs/operators';
    import { ExtractControlFromParentMixin } from '../mixins/extract-control-from-parent.mixin';
    import { ExtractFormDefinitionMixin } from '../mixins/extract-form-definition.mixin';
    import {
      getMetadata,
      setMetadataMap,
    } from '@rxap/reflect-metadata';

    export const RXAP_FORM_SYSTEM_SHOW_METADATA = 'rxap/form-system/show-function';
    export const RXAP_FORM_SYSTEM_HIDE_METADATA = 'rxap/form-system/hide-function';
    export const RXAP_FORM_SYSTEM_HIDE_SHOW_OPTIONS = 'rxap/form-system/hide-show-options';

    export type ControlHideShowFunction<T = any> = (this: T, control: AbstractControl) => boolean | null;

    export interface ControlHideShowOptions {
      /**
       * Weather the hide/showFunction should be called on root group changes
       */
      rootChange?: boolean;
    }

    export function UseHideFunction(hideFunction: ControlHideShowFunction, options: ControlHideShowOptions = {}) {
      return function (target: any, propertyKey: string) {
        setMetadataMap(propertyKey, hideFunction, RXAP_FORM_SYSTEM_HIDE_METADATA, target);
        if (Object.keys(options).length) {
          setMetadataMap(propertyKey, options, RXAP_FORM_SYSTEM_HIDE_SHOW_OPTIONS, target);
        }
      };
    }

    export function UseShowFunction(showFunction: ControlHideShowFunction, options: ControlHideShowOptions = {}) {
      return function (target: any, propertyKey: string) {
        setMetadataMap(propertyKey, showFunction, RXAP_FORM_SYSTEM_SHOW_METADATA, target);
        if (Object.keys(options).length) {
          setMetadataMap(propertyKey, options, RXAP_FORM_SYSTEM_HIDE_SHOW_OPTIONS, target);
        }
      };
    }

    export interface ControlHideShowDirective extends ExtractControlFromParentMixin,
                                                      ExtractFormDefinitionMixin {
    }

    @Mixin(ExtractControlFromParentMixin, ExtractFormDefinitionMixin)
    @Directive({
      selector: '[rxapControlHideShow]',
      standalone: true,
    })
    export class ControlHideShowDirective implements OnInit, OnDestroy {

      @Input('rxapControlHideShow')
      public controlId?: string;

      public control!: RxapFormControl;

      private subscription = new Subscription();

      constructor(
        @Inject(Renderer2)
        private readonly renderer: Renderer2,
        @Inject(ElementRef)
        private readonly elementRef: ElementRef,
        @Optional()
        @Inject(ControlContainer)
        private readonly parent: ControlContainer | null,
        @Self()
        @Optional()
        @Inject(NgControl)
        private readonly ngControl: NgControl | null,
      ) {
      }

      public ngOnInit() {

        if (!this.ngControl && !this.parent) {
          throw new Error('Easier the ControlContainer or NgControl must be injectable');
        }

        if (!this.ngControl && !this.controlId) {
          throw new Error('If the NgControl is not injectable then the control id must be defined!');
        }

        const control = this.ngControl?.control ?? this.extractControlFromParent(this.parent!, this.controlId!);

        if (!(control instanceof RxapFormControl)) {
          throw new Error('The control is not an instance of RxapFormControl');
        }

        this.control = control;

        const formDefinition = this.extractFormDefinition(control);

        const hideFunction = this.extractHideFunction(formDefinition);

        const showFunction = this.extractShowFunction(formDefinition);

        const options = this.extractOptions(formDefinition);

        let changeTrigger = formDefinition.rxapFormGroup.valueChanges;

        if (options.rootChange) {
          changeTrigger = formDefinition.rxapFormGroup.root.valueChanges;
        }

        changeTrigger = changeTrigger.pipe(startWith(null));

        if (showFunction) {
          this.subscription.add(
            changeTrigger.pipe(
              tap(() => {
                // TODO : resubscribe if the showFunction throws an error
                const show = showFunction.call(formDefinition, control);

                switch (show) {

                  case true:
                    this.show();
                    break;

                  case false:
                    this.hide();
                    break;

                  case null:
                    this.reset();
                    break;

                }

              }),
              catchError(err => {
                console.error(err);
                return of(null);
              }),
            ).subscribe(),
          );
        }

        if (hideFunction) {
          this.subscription.add(
            changeTrigger.pipe(
              tap(() => {
                // TODO : resubscribe if the hideFunction throws an error
                const hide = hideFunction.call(formDefinition, control);

                switch (hide) {

                  case true:
                    this.hide();
                    break;

                  case false:
                    this.show();
                    break;

                  case null:
                    this.reset();
                    break;

                }

              }),
              catchError(err => {
                console.error(err);
                return of(null);
              }),
            ).subscribe(),
          );
        }

      }

      public ngOnDestroy() {
        this.subscription.unsubscribe();
      }

      private extractOptions(formDefinition: FormDefinition): ControlHideShowOptions {
        const map = getMetadata<Map<string, ControlHideShowOptions>>(
          RXAP_FORM_SYSTEM_HIDE_SHOW_OPTIONS,
          Object.getPrototypeOf(formDefinition),
        ) ?? null;

        if (!map || !map.has(this.control.controlId)) {
          return {};
        }

        return map.get(this.control.controlId)!;

      }

      private extractHideFunction(formDefinition: FormDefinition): ControlHideShowFunction | null {
        const map = getMetadata<Map<string, ControlHideShowFunction>>(
          RXAP_FORM_SYSTEM_HIDE_METADATA,
          Object.getPrototypeOf(formDefinition),
        ) ?? null;

        if (!map || !map.has(this.control.controlId)) {
          return null;
        }

        return map.get(this.control.controlId)!;

      }

      private extractShowFunction(formDefinition: FormDefinition): ControlHideShowFunction | null {
        const map = getMetadata<Map<string, ControlHideShowFunction>>(
          RXAP_FORM_SYSTEM_SHOW_METADATA,
          Object.getPrototypeOf(formDefinition),
        ) ?? null;

        if (!map || !map.has(this.control.controlId)) {
          return null;
        }

        return map.get(this.control.controlId)!;

      }

      private hide() {
        this.renderer.setStyle(this.elementRef.nativeElement, 'display', 'none');
      }

      private show() {
        this.renderer.setStyle(this.elementRef.nativeElement, 'display', 'block');
      }

      private reset() {
        this.renderer.removeStyle(this.elementRef.nativeElement, 'display');
      }

    }

# results matching ""

# No results matching ""