|
| 1 | +<h1>Getting started with Remote Config <em><abbr title="beta">β<abbr></em></h1> |
| 2 | + |
| 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). |
| 4 | + |
| 5 | +### API: |
| 6 | + |
| 7 | +```ts |
| 8 | +class AngularFireRemoteConfigModule { } |
| 9 | + |
| 10 | +interface ConfigTemplate {[key:string]: string|number|boolean} |
| 11 | + |
| 12 | +type Parameter extends remoteConfig.Value { |
| 13 | + key: string, |
| 14 | + fetchTimeMillis: number |
| 15 | +} |
| 16 | + |
| 17 | +class AngularFireRemoteConfig { |
| 18 | + changes: Observable<Parameter>; |
| 19 | + parameters: Observable<Parameter[]>; |
| 20 | + numbers: Observable<{[key:string]: number|undefined}> & {[key:string]: Observable<number>}; |
| 21 | + booleans: Observable<{[key:string]: boolean|undefined}> & {[key:string]: Observable<boolean>}; |
| 22 | + strings: Observable<{[key:string]: string|undefined}> & {[key:string]: Observable<string|undefined>}; |
| 23 | + |
| 24 | + // from firebase.remoteConfig() proxy: |
| 25 | + activate: () => Promise<boolean>; |
| 26 | + ensureInitialized: () => Promise<void>; |
| 27 | + fetch: () => Promise<void>; |
| 28 | + fetchAndActivate: () => Promise<boolean>; |
| 29 | + getAll: () => Promise<{[key:string]: remoteConfig.Value}>; |
| 30 | + getBoolean: (key:string) => Promise<boolean>; |
| 31 | + getNumber: (key:string) => Promise<number>; |
| 32 | + getString: (key:string) => Promise<string>; |
| 33 | + getValue: (key:string) => Promise<remoteConfig.Value>; |
| 34 | + setLogLevel: (logLevel: remoteConfig.LogLevel) => Promise<void>; |
| 35 | + settings: Promise<remoteConfig.Settings>; |
| 36 | + defaultConfig: Promise<{[key: string]: string | number | boolean}>; |
| 37 | + fetchTimeMillis: Promise<number>; |
| 38 | + lastFetchStatus: Promise<remoteConfig.FetchStatus>; |
| 39 | +} |
| 40 | + |
| 41 | +// Pipes for working with .changes and .parameters |
| 42 | +filterRemote: () => MonoTypeOperatorFunction<Parameter | Parameter[]> |
| 43 | +filterFresh: (interval: number) => MonoTypeOperatorFunction<Parameter | Parameter[]> |
| 44 | +budget: <T>(interval: number) => MonoTypeOperatorFunction<T> |
| 45 | + |
| 46 | +// scanToObject is for use with .changes |
| 47 | +scanToObject: () => OperatorFunction<Parameter, {[key: string]: string|undefined}> |
| 48 | + |
| 49 | +// mapToObject is the same behavior are scanToObject but for use with .parameters, |
| 50 | +mapToObject: () => OperatorFunction<Parameter[], {[key: string]: string|undefined}> |
| 51 | + |
| 52 | +SETTINGS = InjectionToken<remoteConfig.Settings>; |
| 53 | +DEFAULTS = InjectionToken<ConfigTemplate>; |
| 54 | +``` |
| 55 | + |
| 56 | +## Configuration with Dependency Injection |
| 57 | + |
| 58 | +### Configure Remote Config with `SETTINGS` |
| 59 | + |
| 60 | +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). |
| 61 | + |
| 62 | +### Configure default values with `DEFAULTS` |
| 63 | + |
| 64 | +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). |
| 65 | + |
| 66 | +## Putting it all together: |
| 67 | + |
| 68 | +```ts |
| 69 | +@NgModule({ |
| 70 | + imports: [ |
| 71 | + AngularFireModule.initializeApp(environment.firebase), |
| 72 | + AngularFireRemoteConfigModule |
| 73 | + ], |
| 74 | + providers: [ |
| 75 | + { provide: DEFAULT_CONFIG, useValue: { enableAwesome: true } }, |
| 76 | + { |
| 77 | + provide: REMOTE_CONFIG_SETTINGS, |
| 78 | + useFactory: () => isDevMode() ? { minimumFetchIntervalMillis: 10_000 } : {} |
| 79 | + } |
| 80 | + ] |
| 81 | +}) |
| 82 | +export class AppModule { } |
| 83 | + |
| 84 | +... |
| 85 | + |
| 86 | +constructor(remoteConfig: AngularFireRemoteConfig) { |
| 87 | + remoteConfig.changes.pipe( |
| 88 | + filterFresh(172_800_000), // ensure we have values from at least 48 hours ago |
| 89 | + first(), |
| 90 | + // scanToObject when used this way is similar to defaults |
| 91 | + // but most importantly smart-casts remote config values and adds type safety |
| 92 | + scanToObject({ |
| 93 | + enableAwesome: true, |
| 94 | + titleBackgroundColor: 'blue', |
| 95 | + titleFontSize: 12 |
| 96 | + }) |
| 97 | + ).subscribe(…); |
| 98 | + |
| 99 | + // all remote config values cast as strings |
| 100 | + remoteConfig.strings.subscribe(...) |
| 101 | + remoteConfig.booleans.subscribe(...); // as booleans |
| 102 | + remoteConfig.numbers.subscribe(...); // as numbers |
| 103 | + |
| 104 | + // convenience for observing a single string |
| 105 | + remoteConfig.strings.titleBackgroundColor.subscribe(...); |
| 106 | + remoteConfig.booleans.enableAwesome.subscribe(...); // boolean |
| 107 | + remoteConfig.numbers.titleBackgroundColor.subscribe(...); // number |
| 108 | + |
| 109 | + // however those may emit more than once as the remote config cache fires and gets fresh values from the server |
| 110 | + // you can filter it out of .changes for more control: |
| 111 | + remoteConfig.changes.pipe( |
| 112 | + filter(param => param.key === 'titleBackgroundColor'), |
| 113 | + map(param => param.asString()) |
| 114 | + // budget at most 800ms and return the freshest value possible in that time |
| 115 | + // 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) |
| 116 | + budget(800), |
| 117 | + last() |
| 118 | + ).subscribe(...) |
| 119 | + |
| 120 | + // just like .changes, but scanned as into an array |
| 121 | + remoteConfig.parameters.subscribe(all => ...); |
| 122 | + |
| 123 | + // or make promisified firebase().remoteConfig() calls direct off AngularFireRemoteConfig |
| 124 | + // using our proxy |
| 125 | + remoteConfig.getAll().then(all => ...); |
| 126 | + remoteConfig.lastFetchStatus.then(status => ...); |
| 127 | +} |
| 128 | +``` |
0 commit comments