Created
January 31, 2018 16:27
-
-
Save AVatch/7800945368b24842b07719c0310976c2 to your computer and use it in GitHub Desktop.
Google Analytics (Or any other analytics) + Angular / NGRX
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* src/effects/auth.ts | |
* Similiar pattern for all other Effects | |
*/ | |
import 'rxjs/add/operator/map'; | |
import 'rxjs/add/operator/switchMap'; | |
import 'rxjs/add/operator/catch'; | |
import 'rxjs/add/operator/do'; | |
import { Injectable } from '@angular/core'; | |
import { Location } from '@angular/common'; | |
import { Action } from '@ngrx/store'; | |
import { Effect, Actions } from '@ngrx/effects'; | |
import { Observable } from 'rxjs/Observable'; | |
import { of } from 'rxjs/observable/of'; | |
import { AuthProvider } from '../providers/auth/auth'; | |
import { GaProvider } from '../providers/ga/ga'; | |
import * as auth from '../actions/auth'; | |
@Injectable() | |
export class AuthEffects { | |
constructor( | |
private actions$: Actions, | |
private ga: GaProvider, | |
private authProvider: AuthProvider, | |
) { } | |
/** | |
* LOGIN EFFECTS | |
*/ | |
@Effect() | |
login$: Observable<Action> = this.actions$ | |
.ofType(auth.LOGIN) | |
.map((action:auth.LoginAction) => action.payload) | |
.switchMap((payload) => | |
this.authProvider.login$({username:payload.username, password:payload.password}) | |
.map((res) => new auth.LoginSuccessAction(res)) | |
.catch((err) => of(new auth.LoginFailAction(err))) | |
); | |
/** | |
* REGISTER EFFECTS | |
*/ | |
@Effect() | |
register$:Observable<Action> = this.actions$ | |
.ofType(auth.REGISTER) | |
.map((action:auth.RegisterAction) => action.payload) | |
.switchMap((payload) => | |
this.authProvider.register$(payload) | |
.map((res) => new auth.RegisterSuccessAction({username:payload.username, password:payload.password})) | |
.catch((err) => of(new auth.RegisterFailAction(err))) | |
); | |
@Effect() | |
onRegisterSuccessDoLogin$:Observable<Action> = this.actions$ | |
.ofType(auth.REGISTER_SUCCESS) | |
.map((action:auth.RegisterSuccessAction) => action.payload) | |
.map((payload) => new auth.LoginAction(payload)); | |
/** | |
* LOGOUT EFFECTS | |
*/ | |
@Effect() | |
logout$:Observable<Action> = this.actions$ | |
.ofType(auth.LOGOUT) | |
.map(() => new auth.LogoutSuccessAction()); | |
/** | |
* Google Analytics | |
*/ | |
@Effect({dispatch:false}) | |
logEvent$ = this.actions$ | |
.ofType( | |
auth.LOGIN_SUCCESS, | |
auth.LOGIN_FAIL, | |
auth.REGISTER_SUCCESS, | |
auth.REGISTER_FAIL, | |
auth.PASSWORD_RESET, | |
auth.LOGOUT_SUCCESS, | |
auth.LOGOUT_FAIL | |
) | |
.do((action) => this.ga.logEvent('auth', action.type)); | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* src/providers/ga/ga.ts | |
*/ | |
// You can obtain this from your Google Analytics Tracking JS Code | |
import { GAtrackingId } from '../../environments/keys'; | |
import { Injectable } from '@angular/core'; | |
import { Location } from '@angular/common'; | |
@Injectable() | |
export class GaProvider { | |
constructor(private location:Location) { } | |
private useGA() : boolean { | |
return GAtrackingId && typeof ga !== undefined; | |
} | |
/** | |
* We have a method which injects the Google Analytics Tracking Snipper | |
* with optional override for the userId | |
*/ | |
initGA(userId:string='auto'):void { | |
if (!GAtrackingId) return; | |
let scriptId = 'google-analytics'; | |
if (document.getElementById(scriptId)) { | |
return; | |
} | |
var el = document.createElement('script') as any; | |
el.type = "text/javascript"; | |
el.id = scriptId; | |
el.innerText = ` | |
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ | |
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), | |
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) | |
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); | |
ga('create', '${GAtrackingId}', '${userId}'); | |
`.replace(/\r?\n|\r/g, ''); | |
document.getElementsByTagName("body")[0].appendChild(el); | |
} | |
/** | |
* Wrapper around the pageview call. We strip id's (in this case numbers) | |
* from the urls | |
*/ | |
logPageView(stripIds:boolean=true):void { | |
if(!this.useGA()) { return; } | |
const path:string = this.location.path(); | |
const cleanedPath:string = stripIds ? path.replace(/\d+/g, '<id>') : path; | |
ga('send', 'pageview', cleanedPath); | |
} | |
/** | |
* Wrapper around the event call. This get's called any time we want to | |
* register an event | |
*/ | |
logEvent(category:string, action:string):void { | |
if(!this.useGA()) { return; } | |
ga('send', 'event', category, action); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* src/actions/platform.ts | |
*/ | |
import { Action } from '@ngrx/store'; | |
export const INIT_APP = '[Platform] Init Application'; | |
export const INIT_GA = '[Platform] Init Google Analytics'; | |
export class InitAppAction implements Action { | |
readonly type = INIT_APP; | |
constructor() { } | |
} | |
export class InitGAAction implements Action { | |
readonly type = INIT_GA; | |
constructor() { } | |
} | |
export type All | |
= InitAppAction | |
| InitGAAction; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* src/pages/somePage/somePage.ts (Ionic) | |
* Example of tracking events in page when you are not using router | |
* which is the case w/ Ionic | |
*/ | |
import { Component } from '@angular/core'; | |
import { GaProvider } from '../../providers/ga/ga'; | |
@Component({ | |
selector: 'page', | |
templateUrl: 'page.html', | |
}) | |
export class SomePage { | |
constructor( | |
private ga: GaProvider, | |
) { } | |
/** | |
* On entry lifecycle hook, this is the case w/ Ionic, | |
* but something like ngOnInit is also good place to log | |
* the page if you can't use the router | |
*/ | |
ionViewDidLoad():void { | |
this.ga.logPageView(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment