Angular 4 - 在组件执行之前从服务获取数据

时间:2017-09-05 16:19:01

标签: angular service

我是新手并且不确定我的方法有什么问题,请建议如何解决以下问题。

这是我想要做的,当我访问主应用程序页面时,它从config.service.ts调用getConfigs()并从后端获取数据更新this.configStringSource.next(config)。之后它会重定向到this.router.navigate([' / clone / status']),我没有从config.service.ts获取数据

如果我使用ngAfterContentChecked,则执行config-resolver.service.ts,执行status.component.ts和config-resolver.service.ts按预期获取正确的数据,但我无法从状态获取相同的数据.component.ts使用this.route.data.subscribe,我得到" undefined"。

请参阅下面的完整代码,我们将非常感谢您的帮助。

config.ts

export class Config {
    configID: string;
    sourceDbNodes: string;
    targetDbNodes: string;
}

config.service.ts

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 Subject<Config>();

    // 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());
    }

    getConfig(configID: string) {
      this.configsString$.subscribe(
        data => {
console.log('config-resolver.service.ts configsString$ = ', data[1]);
          return data[1];
      });
    }
}

配置-resolver.service.ts

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 {
    this.configService.configsString$.subscribe(
        data => {
console.log('config-resolver.service.ts data[1] = ', data[1]);
        this.config = data[1];
console.log('config-resolver.service.ts this.config = ', this.config);
     });
console.log('config-resolver.service.ts this.config = ', this.config);
     return this.config;
  }
}

app.module.ts

...
...
import { ConfigService } from './_services/config.service';
import { ConfigResolver } from './_services/config-resolver.service';

@NgModule({
  declarations: [
...
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    AppRouting,
    BrowserAnimationsModule,
  ],
  providers: [ConfigService, ConfigResolver],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.routing.ts

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);

app.component.ts

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']);
  }

}

status.component.ts

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 AfterContentChecked {

  configs: string;
  config: Config;
  servers: Array<any>;
  server: { id: number; name: string; status: string; };

  constructor(private configService:ConfigService,
              private route: ActivatedRoute,
              private router: Router) { }

  ngAfterContentChecked() {
    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);
        }
    );
  }
}

console.log输出

accordion.component.ts:54

accordion.component.ts this.accordions = undefined core.es5.js:2925

Angular正在开发模式下运行。调用enableProdMode()以启用生产模式。 配置-resolver.service.ts:69

config-resolver.service.ts this.config = undefined clone.component.ts:20

clone ngOnInit this.config = undefined status.component.ts:79

status.component.ts data = undefined status.component.ts:80

status.component.ts this.config = undefined status.component.ts:79

status.component.ts data = undefined status.component.ts:80

status.component.ts this.config = undefined status.component.ts:79

status.component.ts data = undefined status.component.ts:80

status.component.ts this.config = undefined 配置-resolver.service.ts:64

config-resolver.service.ts data [1] = {configID:&#34; PRODDB_TO_DEVDB&#34 ;, sourceDbNodes:&#34; dbnode21&#34;,targetDbNodes:&#34; dbnode22&#34;} 配置-resolver.service.ts:66

config-resolver.service.ts this.config = {configID:&#34; PRODDB_TO_DEVDB&#34 ;, sourceDbNodes:&#34; dbnode21&#34;,targetDbNodes:&#34; dbnode22&#34;} app.component.ts:27

app.component.ts sourceDbNode = dbnode11 accordion.component.ts:54

status.component.ts data = undefined status.component.ts:80

status.component.ts this.config = undefined

-

提前感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

你的解析器错了:

this.configService.configsString$.subscribe(
  data => {
    this.config = data[1];
  });
  return this.config;
}

这没有任何意义。您通过订阅一个observable来获取值异步,以便稍后在数据可用时执行回调,并在此异步调用之后立即返回。

正如返回类型的方法所示,只返回一个observable,路由器本身将订阅,并且只有在数据可用时才导航到您的组件:

return this.configService.configsString$.map(
  data => data[1];
});

但这只是第一个问题。由于您订阅主题,路由器将等待主题发出下一个事件。但是永远不会有一个,因为您在更新配置之前刚刚发出了最后一个事件。您需要了解有关可观察量如何工作的更多信息。