NetanelBasal
7/15/2017 - 8:27 PM

NgControlOptionsDirective.ts

import { Directive, ElementRef, forwardRef, Input, Renderer2 } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { fromEvent } from 'rxjs/observable/fromEvent';
import { merge } from 'rxjs/observable/merge';
import { timer } from 'rxjs/observable/timer';
import { Subscription } from 'rxjs/Subscription';

export const DEFAULT_VALUE_ACCESSOR : any = {
  provide: NG_VALUE_ACCESSOR,
  useExisting: forwardRef(() => NgControlOptionsDirective),
  multi: true
};

@Directive({
  selector: 'input[type=text][formControlName][ngControlOptions],input[type=text][formControl][ngControlOptions]',
  providers: [DEFAULT_VALUE_ACCESSOR]
})
export class NgControlOptionsDirective implements ControlValueAccessor {
  events : Subscription;
  onChange;
  onTouched;

  registerOnChange( fn : any ) : void {
    this.onChange = fn;
  }

  registerOnTouched( fn : any ) : void {
    this.onTouched = fn;
  }

  constructor( private renderer : Renderer2, private element : ElementRef ) {
  }

  private _controlOptions = {
    updateOn: 'input',
    debounce: null
  };

  @Input() set ngControlOptions( val ) {
    this._controlOptions = { ...this._controlOptions, ...val };
  }

  ngOnInit() {
    const events = this._controlOptions.updateOn.split(' ').map(event => fromEvent(this.element.nativeElement, event));
    this.events = merge(...events)
      .map(( e : Event ) => ( { type: e.type, value: e.target['value'] }))
      .debounce(event => {
        const debounceValue = this._controlOptions.debounce;
        let time = 0;
        if( typeof debounceValue === 'number' ) {
          time = debounceValue;
        } else if( typeof debounceValue === 'object' ) {
          time = debounceValue[event.type] ? debounceValue[event.type] : 0;
        }
        return timer(time);
      })
      .subscribe(event => {
        this.onChange(event.value);
      });
      
    // this.events = merge(...events)
    //   .map(( e : Event ) => ( {type: e.type, value: e.target[ 'value' ]}))
    //   .let(source => {
    //     if ( this._controlOptions.debounce ) {
    //       return source.debounce(event => {
    //         const time = ...
    //         return timer(time);
    //       });
    //     }
    //     return source;
    //   })
    //   .subscribe(event => {
    //     this.onChange(event.value);
    //   });
  }

  writeValue( value : any ) : void {
    const normalizedValue = value == null ? '' : value;
    this.renderer.setProperty(this.element.nativeElement, 'value', normalizedValue);
  }

  setDisabledState( isDisabled : boolean ) : void {
    this.renderer.setProperty(this.element.nativeElement, 'disabled', isDisabled);
  }

  ngOnDestroy() {
    this.events.unsubscribe();
  }

}