/ng-recaptcha-1

Angular component for Google reCAPTCHA

Primary LanguageTypeScriptMIT LicenseMIT

Angular component for Google reCAPTCHA

ng-recaptcha npm version

MIT licensed Build Status

A simple, configurable, easy-to-start component for handling reCAPTCHA.

Table of contents

  1. Installation
  2. Basic Usage
  3. Working with @angular/forms
  4. API
  5. Examples

Installation

The easiest way is to install trough npm:

npm i ng-recaptcha --save

Basic Usage (see in action)

To start with, you need to import the RecaptchaModule (more on that later):

// app.module.ts
import { RecaptchaModule } from 'ng-recaptcha';
import { BrowserModule }  from '@angular/platform-browser';
import { MyApp } from './app.component.ts';

@NgModule({
  bootstrap: [MyApp],
  declarations: [MyApp],
  imports: [
    BrowserModule,
    RecaptchaModule.forRoot(), // Keep in mind the "forRoot"-magic nuances!
  ],
})
export class MyAppModule { }

Once you have done that, the rest is simple:

// app.component.ts
import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `<re-captcha (resolved)="resolved($event)" siteKey="YOUR_SITE_KEY"></re-captcha>`,
}) export class MyApp {
    resolved(captchaResponse: string) {
        console.log(`Resolved captcha with response ${captchaResponse}:`);
    }
}
// boot.ts
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { MyAppModule } from './app.module.ts';

platformBrowserDynamic().bootstrapModule(MyAppModule);

Playground

You can also play with this demo plunk to get a feel of how this component can be used.

Working with @angular/forms

There are two modules available for you:

import { RecaptchaModule } from 'ng-recaptcha';
import { RecaptchaFormsModule } from 'ng-recaptcha/forms';

If you want your <re-captcha> element to work correctly with [(ngModel)] directive, you need to import the RecaptchaFormsModule into your application module (pretty much like with Angular own '@angular/forms' module).

If you do not rely on Angular forms in your project, you should use the "no-forms" module version, as it does not require the @angular/forms package to be bundled with your code.

API

Input Options

The component supports this options:

  • siteKey
  • theme
  • type
  • size
  • tabIndex
  • badge

They are all pretty well described either in the reCAPTCHA docs, or in the invisible reCAPTCHA docs, so I won't duplicate it here.

Besides specifying these options on the component itself, you can provide a global <re-captcha> configuration - see Configuring the component globally section below.

Events

  • resolved(response: string). Occurs when the captcha resolution value changed. When user resolves captcha, use response parameter to send to the server for verification. This parameter is equivalent to calling grecaptcha.getResponse.

    If the captcha has expired prior to submitting its value to the server, the component will reset the captcha, and trigger the resolved event with response === null.

Methods

  • reset(). Performs a manual captcha reset. This method might be useful if your form validation failed, and you need the user to re-enter the captcha.
  • execute(). Executes the invisible recaptcha. Does nothing if component's size is not set to "invisible". See Invisible reCAPTCHA developers guide for more information.

Examples

Configuring the component globally (see in action)

Some properties are global - including siteKey, size, and others. You can provide them at the module-level using the RECAPTCHA_SETTINGS provider:

import { RECAPTCHA_SETTINGS, RecaptchaSettings } from 'ng-recaptcha';

@NgModule({
  providers: [
    {
      provide: RECAPTCHA_SETTINGS,
      useValue: { siteKey: '<YOUR_KEY>' } as RecaptchaSettings,
    },
  ],
}) export class MyModule { }

Global properties can be overridden on a case-by-case basis - the values on the <re-captcha> component itself take precedence over global settings.

Specifying a different language (see in action)

<re-captcha> supports various languages. By default recaptcha will guess the user's language itself (which is beyond the scope of this lib). But you can override this behavior and provide a specific language to use. The language setting is global, though, and cannot be set on a per-captcha basis. It can be provided like this:

import { RECAPTCHA_LANGUAGE } from 'ng-recaptcha';

@NgModule({
  providers: [
    {
      provide: RECAPTCHA_LANGUAGE,
      useValue: 'fr', // use French language
    },
  ],
}) export class MyModule { }

You can find the list of supported languages in reCAPTCHA docs.

Loading the reCAPTCHA API by yourself (see in action)

By default, the component assumes that the reCAPTCHA API loading will be handled by the RecaptchaLoaderService. However, you can override that by providing your instance of this service to the Angular DI.

The below code snippet is an example of how such a provider can be implemented.

TL;DR: there should be an Observable that eventually resolves to a grecaptcha-compatible object (e.g. grecaptcha itself).

<script src="https://www.google.com/recaptcha/api.js?render=explicit&amp;onload=onloadCallback"></script>

<script>
    // bootstrap the application once the reCAPTCHA api has loaded
    function onloadCallback() {
        System.import('app').catch(function(err) { console.error(err); });
    }
</script>
import { RecaptchaLoaderService } from 'ng-recaptcha';

@Injectable()
export class PreloadedRecaptchaAPIService {
  public ready: Observable<ReCaptchaV2.ReCaptcha>;

  constructor() {
    let readySubject = new BehaviorSubject<ReCaptchaV2.ReCaptcha>(grecaptcha);
    this.ready = readySubject.asObservable();
  }
}

@NgModule({
  providers: [
    {
      provide: RecaptchaLoaderService,
      useValue: new PreloadedRecaptchaAPIService(),
    },
  ],
}) export class MyModule { }

Usage with required in forms (see in action)

It's very easy to put <re-captcha> in an Angular form and have it required - just add the required attribute to the <re-captcha> element. Do not forget to import RecaptchaFormsModule from 'ng-recaptcha/forms'!

@Component({
  selector: 'my-form',
  template: `
  <form>
    <re-captcha
      [(ngModel)]="formModel.captcha"
      name="captcha"
      required
      siteKey="YOUR_SITE_KEY"
    ></re-captcha>
  </form>`,
}) export class MyForm {
  formModel = new MyFormModel();
}

A similar approach can be taken for reactive forms:

@Component({
  selector: 'my-reactive-form',
  template: `
    <form [formGroup]="reactiveForm">
      <re-captcha formControlName="recaptchaReactive"></re-captcha>
      <button [disabled]="reactiveForm.invalid">Submit</button>
    </form>
  `,
}) export class MyReactiveForm {
  reactiveForm: FormGroup;

  ngOnInit() {
    this.reactiveForm = new FormGroup({
      recaptchaReactive: new FormControl(null, Validators.required)
    });
  }
}

Working with invisible reCAPTCHA (see in action)

Working with invisible reCAPTCHA is almost the same as with regular one. First, you need to provide the right size:

<re-captcha size="invisible" ...></re-captcha>

You will also need to invoke the "execute()" method manually. This can be done by either obtaining a reference to RecaptchaComponent via @ViewChild(), or by using inline template reference:

<re-captcha #captchaRef="reCaptcha" ...></re-captcha>
...
<button (click)="captchaRef.execute()">Submit</button>

Normally you would only submit a form when recaptcha response has been received. This can be achieved by reacting to (resolved) event and invoking submit logic when the captcha response is truthy (this will not try to submit the form when recaptcha response has expired). A sample implementation would look like this:

@Component({
  selector: 'my-form',
  template: `
  <form>
    <re-captcha
      #captchaRef="reCaptcha"
      siteKey="YOUR_SITE_KEY"
      size="invisible"
      (resolved)="$event && submit($event)"
    ></re-captcha>
    <button (click)="captchaRef.execute()">Submit</button>
  </form>`,
}) export class MyForm {
  public submit(captchaResponse: string): void {
    this.http.post({
      captcha: captchaResponse,
      /* ... */
    });
  }
}