首页 > 解决方案 > 在ngoninit开始之前等待http get请求完成

问题描述

概括

我在 Angular 上有一个应用程序。我有三个组件:root、 child1 ( tabs.component.ts ) 和child2 ( io.component.ts )。另外,我有一个服务可以向 tomcat 服务器发送 get 和 post 请求。

在child1 中,我有一个ngoninit,我在其中调用服务方法 get。我在child2也有 ngoninit 。child1 的 Ngoninit首先启动。在child1获取请求从服务器获取数据太慢并且来自 child2 的 ngoninit开始之前get.subscribe(data=>this.data=data)

所以问题是来自 child2 的 ngoninit 方法使用data,并且作为 get 请求未返回数据但它填充undefined. 所以,我有下一个序列:

序列(控制台)

试过了

使用async, awaittoPromise()但它不起作用,来自 child2 的 ngoninit所有情况下都在完成之前加载。

一些代码

来自 child1 的 ngOnInit

subsystems: Subsystem[]; //need to ngFor them on html
currentTabId;

constructor(private terminalService: TerminalService) {}

ngOnInit() {
try {
  console.log('child1 ngoninit');
  this.terminalService.getSubsystems().subscribe((data: []) => {
    console.log('get in child1 finished');
    this.subsystems=data;
    this.currentTabId=0;
    this.terminalService.setSubsystem(this.subsystems[this.currentTabId]);
  });
} catch (exception) {
  console.log(exception);
}
}

来自 child2 的 ngOnInit

这里我有一个错误:TypeError: Cannot read property 'name' of undefined

constructor(private terminalService: TerminalService) {}

ngOnInit() {
try {
  console.log('child2 ngoninit');
  this.terminalService
    .getResultsBySubsystem(this.terminalService.getSubsystem().name) //here
    .subscribe((data: Command[])=> {
      console.log(data);
      data.forEach((value)=> {
        this.terminalService.setCurrentResult(value.getCommand+'\n'+value.getResult+'\n');
      });
    });
}
catch (exception) {
  console.log(exception);
  this.terminalService.addCurrentResult(this.CONNECTION_ERROR_MSG);
}
}

终端服务.ts

subsystem: Subsystem;

constructor(private httpClient: HttpClient) {}

getSubsystems() {
  return this.httpClient.get('http://localhost:8080/subsystems');
}

getResultsBySubsystem(name: string) {
  return this.httpClient.get('http://localhost:8080/subsystems/'+name+'/result');
}

getSubsystem() {
  console.log('getSubsystem terminal.service invoking');
  return this.subsystem;
}

setSubsystem(subsystem: Subsystem) {
  console.log('setSubsystem terminal.service invoking ');
  this.subsystem=subsystem;
}

如何在 child2 的ngoninit调用子系统中的变量之前等待获取请求name

更新

谢谢你的回答。我试过Resolve了,但是有

新控制台

如所见,resolve在 get 之后调用,但this.actr.data据我所知,必须调用resolve. 使困惑。

来自 terminal.service 的新 getSubsystems

import {map} from 'rxjs/operators';


subsystem: Subsystem;

constructor(private httpClient: HttpClient) {}

getSubsystems() {
    console.log('getSubsystems in terminal.service invoking');
    return this.httpClient.get<Subsystem[]>('http://localhost:8080/subsystems')
      .pipe(map(value=>{console.log(value); return value;}));
  }

孩子1

subsystems: Subsystem[];
currentTabId;

constructor(private terminalService: TerminalService, private actr: ActivatedRoute) {}

ngOnInit() {
    console.log('child1 ngoninit');
    try {
      this.terminalService.setCurrentResult('Connecting...');
      this.actr.data.subscribe((data: []) => { //this
        console.log('get in child1 finished');
        this.subsystems=data;
        console.log(data);
        this.currentTabId=0;
        this.terminalService.setSubsystem(this.subsystems[this.currentTabId]);
      });
    } catch (exception) {
      console.log(exception);
    }
  }

解决服务

export class ResolverService implements Resolve<any>{

  constructor(private terminalService: TerminalService) { }

  resolve(){
    console.log('resolve');
    return this.terminalService.getSubsystems();
  }
}

解析模块

import {RouterModule, Routes} from '@angular/router';
import {ResolverService} from './services/resolver.service';

const routes: Routes = [
  {
    path: '',
    component: AppComponent,
    resolve: {
      subsystems: ResolverService
    }
  }
];

export const routing = RouterModule.forRoot(routes);

@NgModule({
  declarations: [],
  imports: [CommonModule],
  exports: [RouterModule],
  providers: [ResolverService]
})
export class ResolverModule { }

应用程序模块

import {ResolverModule} from './resolver.module';
import { routing } from './resolver.module';
import {RouterModule} from '@angular/router';

@NgModule({
  declarations: [
    AppComponent,
    TabsComponent,
    IoComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    BrowserAnimationsModule,
    HttpClientModule,
    routing
  ],
  exports: [RouterModule],
  providers: [ResolverModule],
  bootstrap: [AppComponent]
})
export class AppModule { }

这有什么问题?

标签: javascriptangulartypescript

解决方案


我用它解决了APP_INITIALIZER

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import {APP_INITIALIZER, NgModule} from '@angular/core';
import { AppComponent } from './app.component';
import {FormsModule} from '@angular/forms';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { TabsComponent } from './tabs/tabs.component';
import {HttpClientModule} from '@angular/common/http';
import { IoComponent } from './io/io.component';
import {AppConfig} from './config/app.config';

export function loadConfig(config: AppConfig) {
  return () => config.load();
}

@NgModule({
  declarations: [
    AppComponent,
    TabsComponent,
    IoComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    BrowserAnimationsModule,
    HttpClientModule,
  ],
  bootstrap: [AppComponent],
  providers: [
    AppConfig,
    {provide: APP_INITIALIZER, useFactory: loadConfig, deps: [AppConfig], multi: true}
  ]
})
export class AppModule {
}

在加载组件的构造函数之前创建配置文件和load()函数以加载获取请求

应用程序.config.ts

import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {Subsystem} from '../data/subsystem';
import {map} from 'rxjs/operators';

@Injectable()
export class AppConfig {

  private subsystems: Subsystem[] = null;
  private subsystem: Subsystem = null;

  constructor(private http: HttpClient) {

  }

  load() {
    return new Promise((resolve) => {
      this.http
        .get('http://localhost:8080/subsystems')
        .pipe(map(value=>value))
        .subscribe((data: Subsystem[]) => {
          this.subsystems = data;
          resolve(true);
        });
    });
  }

  public getSubsystem() {
    return this.subsystem;
  }

  public setSubsystem(subsystem: Subsystem) {
    this.subsystem=subsystem;
  }

  public getSubsystems() {
    return this.subsystems;
  }

  public setSubsystems(subsystems: Subsystem[]) {
    this.subsystems=subsystems;
  }
}

使用初始化数据

tabs.component.ts

import {Component, OnInit} from '@angular/core';
import {Subsystem} from '../data/subsystem';
import {AppConfig} from '../config/app.config';

@Component({
  selector: 'app-tabs-component',
  templateUrl: 'tabs.component.html',
  styleUrls: ['./tabs.component.css'],
})

export class TabsComponent implements OnInit {

  subsystems: Subsystem[];
  subsystem: Subsystem;
  currentTabId;

  constructor(private config: AppConfig) {
  }

  ngOnInit() {
    this.currentTabId=0;
    this.subsystems=this.config.getSubsystems();
    this.config.setSubsystem(this.subsystems[this.currentTabId]);
    this.subsystem=this.config.getSubsystem();
  }

  tabPressed(id) {
    this.currentTabId=id;
    this.config.setSubsystem(this.subsystems[id]);
    this.subsystem=this.config.getSubsystem();
  }

}

推荐阅读