Angular + Facebook - How to use the Facebook SDK in an Angular App
Other versions available:
This is a quick post to go through the steps to load, initialize and use the Facebook JS SDK in an Angular application.
The below code snippets are from an Facebook login tutorial I posted yesterday, for the full tutorial and live demo of the code see Angular 10 - Facebook Login Tutorial & Example.
Load the Facebook SDK in an Angular App Initializer
The app initializer runs before the Angular app starts up to load and initialize the Facebook SDK, and automatically log the user into the Angular app if they are already logged in with Facebook.
When an app initializer function returns a Promise like this one, the Angular app waits for the promise to be resolved before it starts, so you can be sure that the Facebook SDK is initialized and the FB
object is ready to be used as soon as the Angular app starts.
The app initializer is added to Angular app in the providers
section of the app module (/src/app/app.module.ts
) using the APP_INITIALIZER
injection token. For more info see https://angular.io/api/core/APP_INITIALIZER.
import { AccountService } from '@app/_services';
import { environment } from '@environments/environment';
export function appInitializer(accountService: AccountService) {
return () => new Promise(resolve => {
// wait for facebook sdk to initialize before starting the angular app
window['fbAsyncInit'] = function () {
FB.init({
appId: environment.facebookAppId,
cookie: true,
xfbml: true,
version: 'v8.0'
});
// auto authenticate with the api if already logged in with facebook
FB.getLoginStatus(({authResponse}) => {
if (authResponse) {
accountService.apiAuthenticate(authResponse.accessToken)
.subscribe()
.add(resolve);
} else {
resolve();
}
});
};
// load facebook sdk script
(function (d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) { return; }
js = d.createElement(s); js.id = id;
js.src = "https://connect.facebook.net/en_US/sdk.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
});
}
Add TypeScript type definitions for the Facebook SDK
To add TypeScript support for the Facebook FB
object and its methods follow these two steps.
1. Add the type definitions from @types/facebook-js-sdk
with the following npm command:
npm install --save @types/facebook-js-sdk
2. Then add "facebook-js-sdk"
to the "types"
array in your tsconfig.app.json
file:
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": ["facebook-js-sdk"]
},
"files": [
"src/main.ts",
"src/polyfills.ts"
],
"include": [
"src/**/*.d.ts"
]
}
Use the Facebook SDK in your Angular App!
You're now ready to use the Facebook SDK in your Angular app, as an example here is the account service (/src/app/_services/account.service.ts
) from the Facebook login example project, it uses some Facebook SDK auth methods on lines 43
, 63
and 110
.
import { Injectable } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject, Observable, from, of, EMPTY } from 'rxjs';
import { map, concatMap, finalize } from 'rxjs/operators';
import { environment } from '@environments/environment';
import { Account } from '@app/_models';
const baseUrl = `${environment.apiUrl}/accounts`;
@Injectable({ providedIn: 'root' })
export class AccountService {
private accountSubject: BehaviorSubject<Account>;
public account: Observable<Account>;
constructor(
private router: Router,
private route: ActivatedRoute,
private http: HttpClient
) {
this.accountSubject = new BehaviorSubject<Account>(null);
this.account = this.accountSubject.asObservable();
}
public get accountValue(): Account {
return this.accountSubject.value;
}
login() {
// login with facebook then authenticate with the API to get a JWT auth token
this.facebookLogin()
.pipe(concatMap(accessToken => this.apiAuthenticate(accessToken)))
.subscribe(() => {
// get return url from query parameters or default to home page
const returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/';
this.router.navigateByUrl(returnUrl);
});
}
facebookLogin() {
// login with facebook and return observable with fb access token on success
return from(new Promise<fb.StatusResponse>(resolve => FB.login(resolve)))
.pipe(concatMap(({ authResponse }) => {
if (!authResponse) return EMPTY;
return of(authResponse.accessToken);
}));
}
apiAuthenticate(accessToken: string) {
// authenticate with the api using a facebook access token,
// on success the api returns an account object with a JWT auth token
return this.http.post<any>(`${baseUrl}/authenticate`, { accessToken })
.pipe(map(account => {
this.accountSubject.next(account);
this.startAuthenticateTimer();
return account;
}));
}
logout() {
// revoke app permissions to logout completely because FB.logout() doesn't remove FB cookie
FB.api('/me/permissions', 'delete', null, () => FB.logout());
this.stopAuthenticateTimer();
this.accountSubject.next(null);
this.router.navigate(['/login']);
}
getAll() {
return this.http.get<Account[]>(baseUrl);
}
getById(id) {
return this.http.get<Account>(`${baseUrl}/${id}`);
}
update(id, params) {
return this.http.put(`${baseUrl}/${id}`, params)
.pipe(map((account: any) => {
// update the current account if it was updated
if (account.id === this.accountValue.id) {
// publish updated account to subscribers
account = { ...this.accountValue, ...account };
this.accountSubject.next(account);
}
return account;
}));
}
delete(id: string) {
return this.http.delete(`${baseUrl}/${id}`)
.pipe(finalize(() => {
// auto logout if the logged in account was deleted
if (id === this.accountValue.id)
this.logout();
}));
}
// helper methods
private authenticateTimeout;
private startAuthenticateTimer() {
// parse json object from base64 encoded jwt token
const jwtToken = JSON.parse(atob(this.accountValue.token.split('.')[1]));
// set a timeout to re-authenticate with the api one minute before the token expires
const expires = new Date(jwtToken.exp * 1000);
const timeout = expires.getTime() - Date.now() - (60 * 1000);
const { accessToken } = FB.getAuthResponse();
this.authenticateTimeout = setTimeout(() => {
this.apiAuthenticate(accessToken).subscribe();
}, timeout);
}
private stopAuthenticateTimer() {
// cancel timer for re-authenticating with the api
clearTimeout(this.authenticateTimeout);
}
}
Need Some Facebook Help?
Search fiverr for freelance Facebook developers.
Follow me for updates
When I'm not coding...
Me and Tina are on a motorcycle adventure around Australia.
Come along for the ride!