【问题标题】:Angular 4 - getting data from service before component getting executedAngular 4 - 在组件执行之前从服务中获取数据
【发布时间】:2018-02-14 00:19:58
【问题描述】:

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

这是我想要做的,当我访问主应用程序页面时,它从 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 按预期获取正确数据之前执行,但我无法从 status 中获取相同的数据.component.ts 使用 this.route.data.subscribe,我得到“未定义”。

请查看下面的完整代码,我们将不胜感激。

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

config-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 输出

手风琴.component.ts:54

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

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

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

克隆 ngOnInit this.config = undefined status.component.ts:79

status.component.ts 数据 = 未定义 status.component.ts:80

status.component.ts this.config = 未定义 status.component.ts:79

status.component.ts 数据 = 未定义 status.component.ts:80

status.component.ts this.config = 未定义 status.component.ts:79

status.component.ts 数据 = 未定义 status.component.ts:80

status.component.ts this.config = 未定义 config-resolver.service.ts:64

config-resolver.service.ts 数据[1] = {configID:“PRODDB_TO_DEVDB”,sourceDbNodes:“dbnode21”,targetDbNodes:“dbnode22”} config-resolver.service.ts:66

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

app.component.ts sourceDbNode = dbnode11 手风琴.component.ts:54

status.component.ts 数据 = 未定义 status.component.ts:80

status.component.ts this.config = undefined

--

提前感谢您的帮助。

【问题讨论】:

    标签: angular service


    【解决方案1】:

    您的解析器错误:

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

    这没有任何意义。通过订阅一个可观察对象,您将获得一个值异步,以便稍后在数据可用时执行回调,并且在进行此异步调用后,您会立即返回。

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

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

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

    【讨论】:

    • 您好 JB Nizet,感谢您的快速回复。我用 resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable | 修改了我的解析器。承诺 |配置 { 返回 this.configService.configsString$.map(data => data[1]); },现在它甚至没有重定向到克隆/状态组件。请问还有什么遗漏?
    • 阅读我回答的最后一段:您调用 updateConfigs(),它会发出一个事件,然后导航,这会导致路由器订阅,并等待下一个事件,但它从未发出,因为它之前已经发出过。你需要使用一个 BehaviorSubject,或者改变你处理这些东西的方式。
    • 您好 JB Nizet,您非常乐意回答我的问题,再次感谢您。正如我所说,我是 Angular 的新手,刚开始学习我无法以正确的方式做到这一点。你介意给我一些例子,我可以在我的情况下使用 BehaviorSubject 吗?或者我可以采取哪些其他方法来实现这一目标?
    • 您好 JB Nizet,感谢您向我指出链接。根据stackoverflow.com/questions/39066604/…,我在 config-resolver.service.ts 中导入了 'rxjs/add/operator/first' 并将 config.service.ts 修改为 configsString$ = this.configsStringSource.asObservable().first();现在它正在工作。你能确认我在做什么是正确的吗?谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-08
    • 2018-07-22
    • 2017-11-04
    • 1970-01-01
    • 2017-08-10
    • 2018-03-27
    • 1970-01-01
    相关资源
    最近更新 更多