### File

`src/lib/directives/options-from-method.directive.ts`

### Extends

`AfterViewInit` `OnChanges` `ExtractOptionsMethodMixin`

### Implements

`AfterViewInit` `OnChanges`

### Metadata

Selector | `[rxapOptionsFromMethod]`
Standalone | `true`

### Index

###### Properties

- Protected Readonly cdr
- Protected Readonly injector
- Protected matFormField
- Protected method
- Protected ngControl
- Public options
- Protected settings
- Protected Readonly viewContainerRef

###### Methods

- Protected Async loadOptions
- Static ngTemplateContextGuard
- Protected renderTemplate
- Protected setOptions

###### Inputs

- rxapOptionsFromMethodParameters
- rxapOptionsFromMethodResetOnChange

### Inputs

rxapOptionsFromMethodParameters
Type : `Parameters`
Defined in src/lib/directives/options-from-method.directive.ts:54

rxapOptionsFromMethodResetOnChange
Type : `Value`
Defined in src/lib/directives/options-from-method.directive.ts:57

### Methods

Protected Async loadOptions
`loadOptions(parameters?: Parameters)`
Defined in src/lib/directives/options-from-method.directive.ts:93

Parameters :

Name | Type | Optional
parameters | `Parameters` | Yes

Returns : `Promise<ControlOptions>`

Static ngTemplateContextGuard
`ngTemplateContextGuard(dir: OptionsFromMethodDirective, ctx: any)`
Defined in src/lib/directives/options-from-method.directive.ts:46

Parameters :

Name | Type | Optional
dir | `OptionsFromMethodDirective` | No
ctx | `any` | No

Returns : `OptionsFromMethodTemplateContext`

Protected renderTemplate
`renderTemplate()`
Defined in src/lib/directives/options-from-method.directive.ts:97
Returns : `void`

Protected setOptions
`setOptions(options: ControlOptions)`
Defined in src/lib/directives/options-from-method.directive.ts:117

Parameters :

Name | Type | Optional
options | `ControlOptions` | No

Returns : `void`

### Properties

Protected Readonly cdr
Type : `ChangeDetectorRef`
Default value : `inject(ChangeDetectorRef)`
Defined in src/lib/directives/options-from-method.directive.ts:66

Protected Readonly injector
Type : `Injector`
Default value : `inject(INJECTOR)`
Defined in src/lib/directives/options-from-method.directive.ts:65

Protected matFormField
Type : `MatFormField | null`
Default value : `null`
Defined in src/lib/directives/options-from-method.directive.ts:61

Protected method
Type : `Method<ControlOptions | Parameters>`
Defined in src/lib/directives/options-from-method.directive.ts:63

Protected ngControl
Type : `NgControl | null`
Default value : `null`
Defined in src/lib/directives/options-from-method.directive.ts:60

Public options
Type : `ControlOptions | null`
Default value : `null`
Defined in src/lib/directives/options-from-method.directive.ts:59

Protected settings
Type : `OptionsFromMethodDirectiveSettings`
Default value : `{}`
Defined in src/lib/directives/options-from-method.directive.ts:62

Protected Readonly viewContainerRef
Type : `ViewContainerRef`
Default value : `inject(ViewContainerRef)`
Defined in src/lib/directives/options-from-method.directive.ts:64

    import {
      AfterViewInit,
      ChangeDetectorRef,
      Directive,
      inject,
      INJECTOR,
      Injector,
      Input,
      OnChanges,
      SimpleChanges,
      TemplateRef,
      ViewContainerRef,
    } from '@angular/core';
    import { NgControl } from '@angular/forms';
    import { MatFormField } from '@angular/material/form-field';
    import { Mixin } from '@rxap/mixin';
    import { Method } from '@rxap/pattern';
    import {
      ControlOption,
      ControlOptions,
    } from '@rxap/utilities';
    import { ExtractOptionsMethodMixin } from '../mixins/extract-options-method.mixin';

    export interface OptionsFromMethodTemplateContext {
      $implicit: ControlOption;
    }

    // eslint-disable-next-line @typescript-eslint/no-empty-interface
    export interface OptionsFromMethodDirectiveSettings {
    }

    // eslient-disable-next-line @typescript-eslint/no-empty-interface
    export interface OptionsFromMethodDirective<Value = any, Parameters = any>
      extends AfterViewInit, OnChanges, ExtractOptionsMethodMixin {
    }

    @Mixin(ExtractOptionsMethodMixin)
    @Directive({
      // eslint-disable-next-line @angular-eslint/directive-selector
      selector: '[rxapOptionsFromMethod]',
      standalone: true,
    })
    export class OptionsFromMethodDirective<Value = any, Parameters = any> implements AfterViewInit, OnChanges {

      static ngTemplateContextGuard(
        dir: OptionsFromMethodDirective,
        ctx: any,
      ): ctx is OptionsFromMethodTemplateContext {
        return true;
      }

      @Input('rxapOptionsFromMethodParameters')
      public parameters?: Parameters;

      @Input('rxapOptionsFromMethodResetOnChange')
      public resetOnChange?: Value;

      public options: ControlOptions | null                                          = null;
      protected ngControl: NgControl | null                                          = null;
      protected matFormField: MatFormField | null                                    = null;
      protected settings: OptionsFromMethodDirectiveSettings                         = {};
      protected method!: Method<ControlOptions, Parameters>;
      protected readonly viewContainerRef: ViewContainerRef                          = inject(ViewContainerRef);
      protected readonly injector: Injector                                          = inject(INJECTOR);
      protected readonly cdr: ChangeDetectorRef                                = inject(ChangeDetectorRef);
      private readonly template: TemplateRef<OptionsFromMethodTemplateContext> = inject(TemplateRef);

      public async ngAfterViewInit() {
        this.ngControl    = this.injector.get(NgControl, null);
        this.matFormField = this.injector.get(MatFormField, null);
        this.method       = this.extractOptionsMethod();
        // ensure that the options are loaded. It is possible that the ngOnChange is triggered before the ngAfterViewInit
        // then the options are not loaded.
        if (!this.options) {
          this.setOptions(await this.loadOptions(this.parameters));
        }
      }

      public async ngOnChanges(changes: SimpleChanges) {
        // only try to load the options if the method is defined
        // else the initial load will be triggered in the ngAfterViewInit
        if (!this.method) {
          console.debug('The method is not yet defined');
          return;
        }
        const parametersChanges = changes['parameters'];
        if (parametersChanges) {
          this.setOptions(await this.loadOptions(parametersChanges.currentValue));
        }
      }

      protected async loadOptions(parameters?: Parameters): Promise<ControlOptions> {
        return this.method.call(parameters);
      }

      protected renderTemplate() {

        if (!this.options) {
          throw new Error('The options are not yet loaded');
        }

        this.viewContainerRef.clear();

        for (const option of this.options) {
          this.viewContainerRef.createEmbeddedView(this.template, {$implicit: option});
        }

        if (this.resetOnChange !== undefined) {
          this.control?.reset(this.resetOnChange);
        }

        this.cdr.detectChanges();

      }

      protected setOptions(options: ControlOptions) {
        this.options = options.slice();
        this.renderTemplate();
      }

    }

# results matching ""

# No results matching ""