Angular gurus your help is greatly appreciated in this regard.
Here is what I am trying to do, when I access main app page it calls getConfigs() from config.service.ts and get the data from backend then updates this.configStringSource.next(config). Right after that I am trying to redirect it to this.router.navigate(['/clone/status']), but redirect is not happening.
import { Routes, RouterModule } from '@angular/router';
import { CloneComponent } from './clone/clone.component';
import { StatusComponent } from './status/status.component';
import { ConfigurationComponent } from './configuration/configuration.component';
import { LogsComponent } from './logs/logs.component';
import { ConfigResolver } from './_services/config-resolver.service';
const appRoutes: Routes = [
{ path: 'clone', component: CloneComponent, children: [
{path: 'status', component: StatusComponent, resolve: {config: ConfigResolver} },
]
},
{ path: 'logstream', component: LogstreamComponent },
];
export const AppRouting = RouterModule.forRoot(appRoutes);
export class Config {
configID: string;
sourceDbNodes: string;
targetDbNodes: string;
}
import { Injectable, OnInit } from '@angular/core';
import { Http, Headers, Response } from '@angular/http';
//import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import { Router } from '@angular/router';
import {Subject} from 'rxjs/Subject';
import { Config } from '../_models/config';
@Injectable()
export class ConfigService {
// Observable string source
private configsStringSource = new BehaviorSubject<Config>({ configID: "", sourceDbNodes: "", targetDbNodes: ""});
// Observable string stream
configsString$ = this.configsStringSource.asObservable();
// Service message commands
updateConfigs(configs: Config) {
this.configsStringSource.next(configs)
}
constructor(private http: Http, private router:Router) { }
getConfigs() {
let headers = new Headers();
headers.append('Content-Type','application/json');
return this.http.get('http://localhost:8080/sample1/api/config', { headers: headers })
.map((response: Response) => response.json());
}
}
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { Injectable } from '@angular/core';
import { ConfigService } from './config.service';
import { Config } from '../_models/config';
interface Server {
id: number;
name: string;
status: string;
}
@Injectable()
export class ConfigResolver implements Resolve<Config> {
config: Config;
constructor(private configService: ConfigService) {}
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Config> | Promise<Config> | Config {
return this.configService.configsString$.map(
data => data[1]);
}
}
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { Config } from './_models/config';
import { ConfigService } from './_services/config.service';
@Component({
moduleId: module.id.toString(),
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
configs: Config[];
constructor(private router:Router, private configService:ConfigService ) { }
title = 'Angular 4 Proeject';
private getConfigs() {
this.configService.getConfigs().subscribe(configs => {
this.configs = configs;
this.configService.updateConfigs(configs);
console.log('app.component.ts sourceDbNode = '+this.configs[0].sourceDbNodes);
});
}
ngOnInit() {
this.getConfigs();
this.router.navigate(['/clone/status']);
}
}
import { Component, Input, OnInit, AfterContentChecked } from '@angular/core';
import { ActivatedRoute, Params, Router, Data } from '@angular/router';
import { Config } from '../_models/config';
import { ConfigService } from '../_services/config.service';
@Component({
selector: 'app-status',
template: `
<p>
status Works! {{config}}
</p>
`,
styleUrls: ['./status.component.scss']
})
export class StatusComponent implements OnInit {
configs: string;
config: Config;
servers: Array<any>;
server: { id: number; name: string; status: string; };
constructor(private configService:ConfigService,
private route: ActivatedRoute,
private router: Router) { }
ngOnInit() {
this.route.data.subscribe(
(data: Data) => {
this.config = data['config'];
console.log('status.component.ts data = ', data['config']);
console.log('status.component.ts this.config = ', this.config);
}
);
}
}
Your issue is that resolved observables need to complete, so you just need to add .take(1) or .first() to your resolver observable like:
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Config> | Promise<Config> | Config {
return this.configService.configsString$.map(
data => data[1]).take(1);
}
However, there's a much cleaner way of loading a config service:
import { Injectable, APP_INITIALIZER } from '@angular/core';
import { Config } from './_models/config';
@Injectable()
export class ConfigService {
protected config: Config;
constructor(private http: Http) {
}
getConfigs(): Observable<any> {
let headers = new Headers();
headers.append('Content-Type','application/json');
return this.http.get('http://localhost:8080/sample1/api/config', { headers: headers })
.map((response: Response) => response.json());
}
public load() {
return new Promise((resolve, reject) => {
this.getConfigs()
.subscribe(
config => {
this.config = config;
resolve(true);
},
err => resolve(err)
);
});
}
}
export function ConfigServiceInitFactory(configService: ConfigService) {
return () => configService.load();
}
export const ConfigServiceInitProvider = {
provide: APP_INITIALIZER,
useFactory: ConfigServiceInitFactory,
deps: [ConfigService],
multi: true
}
then in your app module, import both ConfigService and ConfigServiceInitProvider and provide them both like this:
providers: [
ConfigService,
ConfigServiceInitProvider,
... remaining service providers..
]
this will ensure that your config is loaded before pretty much anything else, and you can inject your config service where ever it's needed and the config will always be available in a synchronous manner.
It helped to me. In config.service change
// Observable string stream
configsString$ = this.configsStringSource.asObservable();
to stack.
Add .first() to .asObservable().
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With