文章内容

2020/6/24 9:52:54,作 者: 黄兵

angular 代码示例 directive


import {AfterViewInit, Directive, ElementRef, EventEmitter, forwardRef, Injector, Input, NgZone, OnInit, Output} from '@angular/core';
import {AbstractControl, ControlValueAccessor, NG_VALUE_ACCESSOR, NgControl, Validators} from '@angular/forms';
import {ReCaptchaAsyncValidator} from '../../service/ReCaptcha.service';

export interface ReCaptchaConfig {
  theme?: 'dark' | 'light';
  type?: 'audio' | 'image';
  size?: 'compact' | 'normal';
  tabindex?: number;
}

declare global {
  interface Window {
    grecaptcha: any;
    reCaptchaLoad: () => void;
  }
}

@Directive({
  // tslint:disable-next-line:directive-selector
  selector: '[nbRecaptcha]',
  exportAs: 'nbRecaptcha',
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => ReCaptchaDirective),
      multi: true
    },
    ReCaptchaAsyncValidator
  ]
})

export class ReCaptchaDirective implements OnInit, AfterViewInit, ControlValueAccessor {
  @Input() key: string;
  @Input() config: ReCaptchaConfig = {};
  @Input() lang: string;

  @Output() captchaResponse = new EventEmitter();
  @Output() captchaExpired = new EventEmitter();

  private control: AbstractControl;
  private widgetId: number;
  declare const;

  private onChange: (value: string) => void;
  private onTouched: (value: string) => void;

  constructor(private element: ElementRef,
              private  ngZone: NgZone,
              private injector: Injector,
              private reCaptchaAsyncValidator: ReCaptchaAsyncValidator) {
  }

  ngOnInit() {
    this.registerReCaptchaCallback();
    this.addScript();
  }

  registerReCaptchaCallback() {
    window.reCaptchaLoad = () => {
      const config = {
        ...this.config,
        sitekey: this.key,
        callback: this.onSuccess.bind(this),
        'expired-callback': this.onExpired.bind(this)
      };
      this.widgetId = this.render(this.element.nativeElement, config);
    };
  }

  ngAfterViewInit() {
    this.control = this.injector.get(NgControl).control;
    this.setValidators();
  }

  /**
   * @returns empDetails {number}
   * @description Useful for multiple captcha
   */
  getId() {
    return this.widgetId;
  }

  /**
   * Calling the setValidators doesn't trigger any update or value change event.
   * Therefore, we need to call updateValueAndValidity to trigger the update
   */
  private setValidators() {
    this.control.setValidators(Validators.required);
    this.control.updateValueAndValidity();
  }

  writeValue(obj: any): void {
  }

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

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

  /**
   * onExpired
   */
  onExpired() {
    this.ngZone.run(() => {
      this.captchaExpired.emit();
      this.onChange(null);
      this.onTouched(null);
    });
  }

  /**
   *
   * @param empDetails response
   * @description token
   */
  onSuccess(token: string) {
    this.ngZone.run(() => {
      this.verifyToken(token);
      this.captchaResponse.next(token);
      this.onChange(token);
      this.onTouched(token);
    });
  }

  /**
   *
   * @param empDetails token
   */
  verifyToken(token: string) {
    this.control.setAsyncValidators(this.reCaptchaAsyncValidator.validateToken(token));
    this.control.updateValueAndValidity();
  }

  /**
   * Renders the container as a reCAPTCHA widget and returns the ID of the newly created widget.
   * @param empDetails element
   * @param empDetails config
   * @returns empDetails {number}
   */
  private render(element: HTMLElement, config): number {
    return window.grecaptcha.render(element, config);
  }

  /**
   * Resets the reCAPTCHA widget.
   */
  reset(): void {
    if (!this.widgetId) {
      return;
    }
    window.grecaptcha.reset(this.widgetId);
    this.onChange(null);
  }

  /**
   * Gets the response for the reCAPTCHA widget.
   * @returns empDetails {string}
   */
  getResponse(): string {
    if (!this.widgetId) {
      return window.grecaptcha.getResponse(this.widgetId);
    }
  }

  /**
   * Add the script
   */
  addScript() {
    const script = document.createElement('script');
    const lang = this.lang ? '&hl=' + this.lang : '';
    script.src = `https://recaptcha.net/recaptcha/api.js?onload=reCaptchaLoad&render=explicit${lang}`;
    script.async = true;
    script.defer = true;
    document.body.appendChild(script);
  }
}


分享到:

发表评论

评论列表