Skip to content

Commit b46b382

Browse files
committed
Docs and cleanup
1 parent 05c840b commit b46b382

File tree

6 files changed

+227
-33
lines changed

6 files changed

+227
-33
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ Firebase offers two cloud-based, client-accessible database solutions that suppo
104104

105105
- [Getting started with Firebase Messaging](docs/messaging/messaging.md)
106106

107-
### **NEW:** Change behavior and appearance of your application without deploying
107+
### **BETA:** Change behavior and appearance of your application without deploying
108108

109109
> Firebase Remote Config is a cloud service that lets you change the behavior and appearance of your app without requiring users to download an app update. [Learn more about Remote Config](https://firebase.google.com/docs/remote-config).
110110

docs/analytics/getting-started.md

Lines changed: 94 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,113 @@
11
# Getting started with Google Analytics
22

3-
### Something, something
3+
`AngularFireAnalytics` dynamic imports the `firebase/analytics` library and provides a promisified version of the [Firebase Analytics SDK (`firebase.analytics.Analytics`)](https://firebase.google.com/docs/reference/js/firebase.analytics.Analytics.html).
44

5-
TBD
5+
### Usage:
66

7-
### Putting it all together
7+
```ts
8+
import { AngularFireAnalyticsModule } from '@angular/fire/analytics';
9+
10+
@NgModule({
11+
imports: [
12+
AngularFireModule.initializeApp(environment.firebase),
13+
AngularFireAnalyticsModule
14+
]
15+
})
16+
export class AppModule { }
17+
```
18+
19+
`AngularFireAnalyticsModule` will dyanamically import and configure `firebase/analytics`. A `page_view` event will automatically be logged (see `CONFIG` below if you wish to disable this behavior.)
20+
21+
In your component you can then dependency inject `AngularFireAnalytics` and make calls against the SDK:
22+
23+
```ts
24+
import { AngularFireAnalytics } from '@angular/fire/analytics';
25+
26+
constructor(analytics: AngularFireAnalytics) {
27+
analytics.logEvent('custom_event', { ... });
28+
}
29+
```
30+
31+
## Tracking Screen Views
32+
33+
You can log [`screen_view` events](https://firebase.google.com/docs/reference/js/firebase.analytics.Analytics.html#parameters_10) yourself of course, but AngularFire provides the `ScreenTrackingService` which automatically integrates with the Angular Router to provide Firebase with screen view tracking. You simply can integrate like so:
834

935
```ts
36+
import { AngularFireAnalyticsModule, ScreenTrackingService } from '@angular/fire/analytics';
37+
38+
@NgModule({
39+
imports: [
40+
AngularFireModule.initializeApp(environment.firebase),
41+
AngularFireAnalyticsModule
42+
],
43+
providers: [
44+
ScreenTrackingService
45+
]
46+
})
47+
export class AppModule { }
48+
```
49+
50+
`AngularFireAnalyticsModule` will initialize `ScreenTrackingService` if it is provided.
51+
52+
## Tracking User Identifiers
53+
54+
To enrich your Analytics data you can track the currently signed in user by setting [`setuserid`](https://firebase.google.com/docs/reference/js/firebase.analytics.Analytics.html#setuserid) and [`setUserProperties`](https://firebase.google.com/docs/reference/js/firebase.analytics.Analytics.html#set-user-properties). AngularFire provides a `UserTrackingService` which will dynamically import `firebase/auth`, monitor for changes in the logged in user, and call `setuserid` for you automatically.
55+
56+
57+
```ts
58+
import { AngularFireAnalyticsModule, UserTrackingService } from '@angular/fire/analytics';
59+
1060
@NgModule({
1161
imports: [
1262
AngularFireModule.initializeApp(environment.firebase),
1363
AngularFireAnalyticsModule
1464
],
1565
providers: [
16-
ScreenTrackingService,
1766
UserTrackingService
1867
]
1968
})
2069
export class AppModule { }
2170
```
2271

72+
`AngularFireAnalyticsModule` will initialize `UserTrackingService` if it is provided.
73+
74+
## Configuration with Dependency Injection
75+
76+
### Configure Google Analtyics with `CONFIG`
77+
78+
Using the `CONFIG` DI Token (*default: {}*) will allow you to configure Google Analytics. E.g, you could skip sending the initial `page_view` event, anonymize IP addresses, and disallow ads personalization signals for all events like so:
79+
2380
```ts
24-
constructor(analytics: AngularFireAnalytics) {
25-
analytics.logEvent('custom_event', { ... });
26-
}
27-
```
81+
import { AngularFireAnalyticsModule, CONFIG } from '@angular/fire/analytics';
82+
83+
@NgModule({
84+
imports: [
85+
AngularFireModule.initializeApp(environment.firebase),
86+
AngularFireAnalyticsModule
87+
],
88+
providers: [
89+
{ provide: CONFIG, useValue: {
90+
send_page_view: false,
91+
allow_ad_personalization_signals: false,
92+
anonymize_ip: true
93+
} }
94+
]
95+
})
96+
export class AppModule { }
97+
```
98+
99+
See the gtag.js documentation to learn of the different configuration options at your disposal.
100+
101+
### Use DebugView `DEBUG_MODE`
102+
103+
To use [DebugView in Analtyics](https://console.firebase.google.com/project/_/analytics/debugview) set `DEBUG_MODE` to `true` (*default: false*).
104+
105+
### Track deployments with `APP_NAME` and `APP_VERSION`
106+
107+
If you provide `APP_NAME` and `APP_VERSION` (*default: undefined*) you will be able to [track version adoption](https://console.firebase.google.com/project/_/analytics/latestrelease) of your PWA.
108+
109+
### Disable analytics collection via `COLLECTION_ENABLED`
110+
111+
If you set `COLLECTION_ENABLED` (*default: true*) to `false` then analytics collection will be disabled for this app on this device. To opt back in to analytics collection you could then call `setAnalyticsCollectionEnabled(true)`.
112+
113+
Putting these APIs to use with cookies would allow you to create a flexible analytics collection scheme that would respect your user's desire for privacy.

docs/remote-config/getting-started.md

Lines changed: 100 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,63 @@
1-
# Getting started with Remote Config
1+
<h1>Getting started with Remote Config <em><abbr title="beta">β<abbr></em></h1>
22

3-
### Something, something
3+
`AngularFireRemoteConfig` dynamically imports the `firebase/remote-config` library on demand, provides convenience observables, pipes, and a promisified version of the [Firebase Remote Config SDK (`firebase.remoteConfig.RemoteConfig`)](https://firebase.google.com/docs/reference/js/firebase.remoteconfig.RemoteConfig).
44

5-
TBD
5+
### API:
66

7-
### Putting it all together
7+
```ts
8+
interface ConfigTemplate {[key:string]: string|number|boolean}
9+
10+
type Parameter extends remoteConfig.Value {
11+
key: string,
12+
fetchTimeMillis: number
13+
}
14+
15+
class AngularFireRemoteConfig {
16+
changes: Observable<Parameter>;
17+
parameters: Observable<Parameter[]>;
18+
numbers: Observable<{[key:string]: number|undefined}> & {[key:string]: Observable<number>};
19+
booleans: Observable<{[key:string]: boolean|undefined}> & {[key:string]: Observable<boolean>};
20+
strings: Observable<{[key:string]: string|undefined}> & {[key:string]: Observable<string|undefined>};
21+
22+
// from firebase.remoteConfig() proxy:
23+
activate: () => Promise<boolean>;
24+
ensureInitialized: () => Promise<void>;
25+
fetch: () => Promise<void>;
26+
fetchAndActivate: () => Promise<boolean>;
27+
getAll: () => Promise<{[key:string]: remoteConfig.Value}>;
28+
getBoolean: (key:string) => Promise<boolean>;
29+
getNumber: (key:string) => Promise<number>;
30+
getString: (key:string) => Promise<string>;
31+
getValue: (key:string) => Promise<remoteConfig.Value>;
32+
setLogLevel: (logLevel: remoteConfig.LogLevel) => Promise<void>;
33+
settings: Promise<remoteConfig.Settings>;
34+
defaultConfig: Promise<{[key: string]: string | number | boolean}>;
35+
fetchTimeMillis: Promise<number>;
36+
lastFetchStatus: Promise<remoteConfig.FetchStatus>;
37+
}
38+
39+
// Pipes for working with .changes and .parameters
40+
filterRemote: () => MonoTypeOperatorFunction<Parameter | Parameter[]>
41+
filterFresh: (interval: number) => MonoTypeOperatorFunction<Parameter | Parameter[]>
42+
budget: <T>(interval: number) => MonoTypeOperatorFunction<T>
43+
44+
// scanToObject is for use with .changes
45+
scanToObject: () => OperatorFunction<Parameter, {[key: string]: string|undefined}>
46+
// mapToObject is the same behavior are scanToObject but for use with .parameters,
47+
mapToObject: () => OperatorFunction<Parameter[], {[key: string]: string|undefined}>
48+
```
49+
50+
## Configuration with Dependency Injection
51+
52+
### Configure Remote Config with `SETTINGS`
53+
54+
Using the `SETTINGS` DI Token (*default: {}*) will allow you to [configure Firebase Remote Config](https://firebase.google.com/docs/reference/js/firebase.remoteconfig.Settings.html).
55+
56+
### Configure default values with `DEFAULTS`
57+
58+
Providing `DEFAULTS ({[key: string]: string | number | boolean})` has `AngularFireRemoteConfig` emit the provided defaults first, which allows you to count on Remote Config when the user is offline or in environments that the Remote Config service does not handle (i.e, Server Side Rendering).
59+
60+
## Putting it all together:
861

962
```ts
1063
@NgModule({
@@ -16,15 +69,54 @@ TBD
1669
{ provide: DEFAULT_CONFIG, useValue: { enableAwesome: true } },
1770
{
1871
provide: REMOTE_CONFIG_SETTINGS,
19-
useFactory: () => isDevMode ? { minimumFetchIntervalMillis: 1 } : {}
72+
useFactory: () => isDevMode() ? { minimumFetchIntervalMillis: 10_000 } : {}
2073
}
2174
]
2275
})
2376
export class AppModule { }
24-
```
2577

26-
```ts
78+
...
79+
2780
constructor(remoteConfig: AngularFireRemoteConfig) {
28-
remoteConfig.changes.subscribe(changes => …);
81+
remoteConfig.changes.pipe(
82+
filterFresh(172_800_000), // ensure we have values from at least 48 hours ago
83+
first(),
84+
// scanToObject when used this way is similar to defaults
85+
// but most importantly smart-casts remote config values and adds type safety
86+
scanToObject({
87+
enableAwesome: true,
88+
titleBackgroundColor: 'blue',
89+
titleFontSize: 12
90+
})
91+
).subscribe(…);
92+
93+
// all remote config values cast as strings
94+
remoteConfig.strings.subscribe(...)
95+
remoteConfig.booleans.subscribe(...); // as booleans
96+
remoteConfig.numbers.subscribe(...); // as numbers
97+
98+
// convenience for observing a single string
99+
remoteConfig.strings.titleBackgroundColor.subscribe(...);
100+
remoteConfig.booleans.enableAwesome.subscribe(...); // boolean
101+
remoteConfig.numbers.titleBackgroundColor.subscribe(...); // number
102+
103+
// however those may emit more than once as the remote config cache fires and gets fresh values from the server
104+
// you can filter it out of .changes for more control:
105+
remoteConfig.changes.pipe(
106+
filter(param => param.key === 'titleBackgroundColor'),
107+
map(param => param.asString())
108+
// budget at most 800ms and return the freshest value possible in that time
109+
// our budget pipe is similar to timeout but won't error or abort the pending server fetch (it won't emit it, if the deadline is exceeded, but it will have been fetched so can use the freshest values on next subscription)
110+
budget(800),
111+
last()
112+
).subscribe(...)
113+
114+
// just like .changes, but scanned as into an array
115+
remoteConfig.parameters.subscribe(all => ...);
116+
117+
// or make promisified firebase().remoteConfig() calls direct off AngularFireRemoteConfig
118+
// using our proxy
119+
remoteConfig.getAll().then(all => ...);
120+
remoteConfig.lastFetchStatus.then(status => ...);
29121
}
30122
```

src/analytics/analytics.module.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ import { AngularFireAnalytics } from './analytics';
77
})
88
export class AngularFireAnalyticsModule {
99
constructor(
10+
analytics: AngularFireAnalytics,
1011
@Optional() screenTracking: ScreenTrackingService,
1112
@Optional() userTracking: UserTrackingService
12-
) { }
13+
) {
14+
// calling anything on analytics will eagerly load the SDK
15+
analytics.app;
16+
}
1317
}

src/analytics/analytics.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ import { map, tap, shareReplay, switchMap } from 'rxjs/operators';
55
import { FirebaseAppConfig, FirebaseOptions, runOutsideAngular, ɵlazySDKProxy, FirebaseAnalytics, FIREBASE_OPTIONS, FIREBASE_APP_NAME, _firebaseAppFactory } from '@angular/fire';
66
import { analytics, app } from 'firebase';
77

8-
export const ANALYTICS_COLLECTION_ENABLED = new InjectionToken<boolean>('angularfire2.analytics.analyticsCollectionEnabled');
8+
export interface Config {[key:string]: any};
99

10+
export const COLLECTION_ENABLED = new InjectionToken<boolean>('angularfire2.analytics.analyticsCollectionEnabled');
1011
export const APP_VERSION = new InjectionToken<string>('angularfire2.analytics.appVersion');
1112
export const APP_NAME = new InjectionToken<string>('angularfire2.analytics.appName');
1213
export const DEBUG_MODE = new InjectionToken<boolean>('angularfire2.analytics.debugMode');
14+
export const CONFIG = new InjectionToken<Config>('angularfire2.analytics.config');
1315

1416
const APP_NAME_KEY = 'app_name';
1517
const APP_VERSION_KEY = 'app_version';
@@ -39,18 +41,19 @@ export class AngularFireAnalytics {
3941
private gtag: (...args: any[]) => void;
4042
private analyticsInitialized: Promise<void>;
4143

42-
async updateConfig(config: {[key:string]: any}) {
44+
async updateConfig(config: Config) {
4345
await this.analyticsInitialized;
4446
this.gtag(GTAG_CONFIG_COMMAND, this.options[ANALYTICS_ID_FIELD], { ...config, update: true });
4547
};
4648

4749
constructor(
4850
@Inject(FIREBASE_OPTIONS) private options:FirebaseOptions,
4951
@Optional() @Inject(FIREBASE_APP_NAME) nameOrConfig:string|FirebaseAppConfig|null|undefined,
50-
@Optional() @Inject(ANALYTICS_COLLECTION_ENABLED) analyticsCollectionEnabled:boolean|null,
52+
@Optional() @Inject(COLLECTION_ENABLED) analyticsCollectionEnabled:boolean|null,
5153
@Optional() @Inject(APP_VERSION) providedAppVersion:string|null,
5254
@Optional() @Inject(APP_NAME) providedAppName:string|null,
5355
@Optional() @Inject(DEBUG_MODE) debugModeEnabled:boolean|null,
56+
@Optional() @Inject(CONFIG) providedConfig:Config|null,
5457
@Inject(PLATFORM_ID) platformId:Object,
5558
zone: NgZone
5659
) {
@@ -75,6 +78,7 @@ export class AngularFireAnalytics {
7578

7679
}
7780

81+
if (providedConfig) { this.updateConfig(providedConfig) }
7882
if (providedAppName) { this.updateConfig({ [APP_NAME_KEY]: providedAppName }) }
7983
if (providedAppVersion) { this.updateConfig({ [APP_VERSION_KEY]: providedAppVersion }) }
8084
if (debugModeEnabled) { this.updateConfig({ [DEBUG_MODE_KEY]: 1 }) }

0 commit comments

Comments
 (0)