I'm developing Angular 2 + TypeScript app.
I need to reset reCaptcha if form is invalid.
But in my typescript code when I write grecaptcha.reset();
, I get error: Can not resolve symbol 'grecaptcha'
How can I reset reCaptcha or resolve/declare grecaptcha
variable and where?
For Typescript, declare grecaptcha
:
declare var grecaptcha: any;
This presumes that the reCAPTCHA api has been included,
<script src='https://www.google.com/recaptcha/api.js?render=explicit'></script>
Alternatively, grecaptcha
can be typed as follows:
declare var grecaptcha: ReCAPTCHA;
ReCAPTCHA Interface
import { ElementRef } from '@angular/core';
/**
* Interface for Google's reCAPTCHA JavaScript API.
*
* Display API
* @see {@link https://developers.google.com/recaptcha/docs/display}
*
* Invisible API
* @see {@link https://developers.google.com/recaptcha/docs/invisible}
*/
export interface ReCAPTCHA {
/**
* Programatically invoke the reCAPTCHA check. Used if the invisible reCAPTCHA is on a div
* instead of a button.
*
* @param {string} opt_widget_id Optional widget ID, defaults to the first widget created if
* unspecified.
*/
execute(opt_widget_id?: string): void;
/**
* Renders the container as a reCAPTCHA widget and returns the ID of the newly created widget.
*
* @param {ElementRef|string} container The HTML element to render the reCAPTCHA widget. Specify
* either the ID of the container (string) or the DOM element itself.
* @param {Object} parameters An object containing parameters as key=value pairs, for example,
* {"sitekey": "your_site_key", "theme": "light"}.
*/
render(container: ElementRef|string, parameters: {[key: string]: string}): void;
/**
* Resets the reCAPTCHA widget.
*
* @param {string} opt_widget_id Optional widget ID, defaults to the first widget created if
* unspecified.
*/
reset(opt_widget_id?: string): void;
/**
* Gets the response for the reCAPTCHA widget. Returns a null if reCaptcha is not validated.
*
* @param {string} opt_widget_id Optional widget ID, defaults to the first widget created if
* unspecified.
*/
getResponse(opt_widget_id?: string): string;
}
Example
The following code is an outline and does not show the server side ReCAPTCHA verification.
ReCAPTCHA Service
import { Injectable, OnInit } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs';
export interface ReCAPTCHAResponse {
success: boolean;
status_code: number,
error_codes?: Array<string>;
}
@Injectable()
export class ReCAPTCHAService {
public recaptchaResponse$: Observable<ReCAPTCHAResponse>;
public constructor(private http: Http) {}
public verifyUserResponse(userResponseToken: string): Observable<ReCAPTCHAResponse> {
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.post('/auth/captcha', {'g-recaptcha-response': userResponseToken}, options)
.map( (res: Response) => this.extractData(res))
.catch( (error: Response | any) => this.handleError(error));
}
private extractData(res: Response): ReCAPTCHAResponse {
const recaptchaResponse: ReCAPTCHAResponse = res.json();
return recaptchaResponse;
}
private handleError (error: Response | any): Observable<ReCAPTCHAResponse> {
let errMsg: string;
if (error instanceof Response) {
let body = error.json() || '';
let err = body.error || JSON.stringify(body);
errMsg = error.status + ' - ' + (error.statusText || '') + ': ' + err;
} else {
errMsg = error.message ? error.message : error.toString();
}
return Observable.throw({ success: false, status_code: 0, error_codes: [errMsg]});
}
}
Component
import { Component, OnDestroy, OnInit } from '@angular/core';
import { ReCAPTCHA } from './recaptcha';
import { ReCAPTCHAResponse, ReCAPTCHAService } from './recaptcha.service';
declare var grecaptcha: ReCAPTCHA;
declare var window: any;
@Component ({
moduleId: module.id,
selector: 'create-account',
templateUrl: 'create-account.component.html'
})
export class CreateAccountComponent implements OnDestroy, OnInit {
public constructor(private recaptcha: ReCAPTCHAService, private formBuilder: FormBuilder) {}
public ngOnInit(): void {
this.buildForms();
// Export reCAPTCHACallback to global scope.
window['reCAPTCHACallback'] = this.reCAPTCHACallback.bind(this);
grecaptcha.render('create-account-captcha', {
'sitekey': 'your-site-key',
'size': 'invisible', // Optional (see docs)
'callback': 'reCAPTCHACallback'
});
}
/**
* Verify reCAPTCHA response on server.
*/
public reCAPTCHACallback(token: string) {
if (token == null /* checks for undefined or null */ || token.length === 0) {
grecaptcha.reset();
// TODO: report that captcha was invalid
} else {
let response$: Observable<ReCAPTCHAResponse>;
response$ = this.recaptcha.verifyUserResponse(token);
response$.subscribe( r => {
if (r.success) {
// TODO: create the new user account
} else {
grecaptcha.reset();
// TODO: report that captcha was invalid
}
},
(error: any) => {
// TODO: handle server error
});
}
}
private buildForms(): void {
// TODO
}
}