Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Use APP_INITIALIZER instead of canActivate #23

Merged
merged 1 commit into from Mar 25, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 0 additions & 2 deletions src/app/app-routing.module.ts
Expand Up @@ -6,7 +6,6 @@ import {
Routes,
} from '@angular/router';

import { RuntimeEnvironmentService } from 'app/core/runtime-environment.service';
import { environment } from 'environments/environment';

// if you don't want to lazy load the features module,
Expand All @@ -20,7 +19,6 @@ import { environment } from 'environments/environment';
const routes: Routes = [
{
path: '',
canActivate: [RuntimeEnvironmentService],
loadChildren: 'app/features/features.module#FeaturesModule',
},
];
Expand Down
13 changes: 11 additions & 2 deletions src/app/core/core.module.ts
@@ -1,5 +1,5 @@
import { HttpClient, HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { APP_INITIALIZER, NgModule } from '@angular/core';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { StoreModule } from '@ngrx/store';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
Expand All @@ -11,7 +11,10 @@ import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
// import 'hammerjs';

import { LANGUAGES } from 'app/core/injection-tokens';
import { RuntimeEnvironmentService } from 'app/core/runtime-environment.service';
import {
initRuntimeEnvironment,
RuntimeEnvironmentService,
} from 'app/core/runtime-environment.service';
import { httpLoaderFactory } from 'app/shared/helpers/aot.helper';
import { metaReducers, reducers } from 'app/shared/states/root.reducer';
import { environment } from 'environments/environment';
Expand Down Expand Up @@ -57,6 +60,12 @@ import { environment } from 'environments/environment';
useValue: ['en', 'fr'],
},
RuntimeEnvironmentService,
{
provide: APP_INITIALIZER,
useFactory: initRuntimeEnvironment,
deps: [RuntimeEnvironmentService],
multi: true,
},
],
})
export class CoreModule {}
75 changes: 47 additions & 28 deletions src/app/core/runtime-environment.service.ts
@@ -1,42 +1,61 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { CanActivate } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
import { catchError, mapTo, tap } from 'rxjs/operators';
import { catchError, tap } from 'rxjs/operators';

import { environment } from 'environments/environment';

// if you decide to use runtime environment,
// you should make sure this interface matches
// what will be returned by the server when
// reaching the environment
export interface IRuntimeEnvironment {}

/**
* runtime environment service allows you to load async data
* - you don't have to rebuild the app to refresh those data
* (like you do when using CLI environment)
* - the `update` method can be used to update it at anytime
* - if you've set `environment.loadRuntimeEnvironment` to true
* angular will wait for the runtime environment to be loaded
* before bootstraping the app, which means you can then inject
* RuntimeEnvironmentService and directly (in a synchronous way)
* use: `this.runtimeEnvironmentService.environment.myVar`
*/
@Injectable()
export class RuntimeEnvironmentService implements CanActivate {
export class RuntimeEnvironmentService {
// you should define the environment type accordingly to your data
public environment: any = {};
public environment: IRuntimeEnvironment = {};

constructor(private http: HttpClient) {}

canActivate(): boolean | Observable<boolean> | Promise<boolean> {
if (environment.loadRuntimeEnvironment) {
// here you can conditionally load the environment of your choice
// for example based on URL
// by default, load runtime-environment
return this.http
.get('assets/runtime-environments/runtime-environment.json')
.pipe(
// TODO: add type
tap(env => (this.environment = env)),
mapTo(true),
catchError(_ => {
console.error(
'Error while trying to fetch the runtime environment'
);

return of(false);
})
);
}

// if environment.loadRuntimeEnvironment is set to false, then we just want
// to move forward and do not 1) load the json file, 2) wait anymore
return true;
update(): Observable<IRuntimeEnvironment> {
// here you can conditionally load an async environment of your choice
// for example based on URL
return this.http
.get<IRuntimeEnvironment>(
'assets/runtime-environments/runtime-environment.json'
)
.pipe(
tap(env => (this.environment = env)),
catchError(_ => {
console.error('Error while trying to fetch the runtime environment');

return of(false);
})
);
}
}

export function initRuntimeEnvironment(
runtimeEnvironmentService: RuntimeEnvironmentService
): () => Promise<IRuntimeEnvironment> {
if (environment.loadRuntimeEnvironment) {
return () => runtimeEnvironmentService.update().toPromise();
}

// if environment.loadRuntimeEnvironment is set
// to false then we just want to move forward
return () => Promise.resolve(null);
}
2 changes: 1 addition & 1 deletion src/app/shared/states/pizzas/pizzas.selectors.ts
Expand Up @@ -31,7 +31,7 @@ export const {
selectTotal: selectPizzaTotal,
} = pizzasAdapter.getSelectors();

// by usgin the createSelector function you'll be able to
// by using the createSelector function you'll be able to
// keep excellent performance thanks to memoization
export const selectCurrentPizzaId = createSelector(
selectPizzasState,
Expand Down