如何从 ngOnInit Angular 中的服务获取数据

Posted

技术标签:

【中文标题】如何从 ngOnInit Angular 中的服务获取数据【英文标题】:How to get data from a service in ngOnInit Angular 【发布时间】:2020-02-12 20:22:20 【问题描述】:

我在尝试从 http 服务获取 ngOnInit 中的数据时遇到问题。当组件被触发时,我需要在 var 中设置我的数据,以便我可以在其他函数中使用它。

我通过执行异步 ngOnInit 并接收来自 Promise 函数的响应来实现这一点,但我认为这不是一个好习惯吗?我该如何改进它?

这是我的代码:

COMPONENT.TS



     async ngOnInit() 
        this.username = localStorage.getItem('username');
        this.segment.value = 'FUNCIONAL';
        this.categoria = this.segment.value;
        this.listadoClases = await this.claseServicio.obtenerListadoClases(this.categoria); // **Need to set this variable at onInit**


SERVICE.TS


    getClases(actividad) 
        return this.http.get(`https://anders-test.herokuapp.com/clases/obtenerPorCategoria/$actividad`);
      


      obtenerListadoClases(categoria) 
        return new Promise(resolve => 
          this.getClases(categoria).subscribe(data => 
            if (data) 
              resolve(data)
            
          )
        )
      

我这样做是因为我试图学习/理解异步/等待。我想稍微升级一下我的代码..但是在阅读了很多之后我没有得到这个想法..

提前谢谢大家!

【问题讨论】:

基本上没问题,虽然有一种更简单的方法可以将 observable 转换为 promise:只需 return this.getClases(cetegoria).toPromise() 【参考方案1】:

Nyco,你到底为什么要把事情搞得这么复杂?

服务

  getClases(actividad) 
        return this.http.get(`https://anders-test.herokuapp.com/clases/obtenerPorCategoria/$actividad`);
      

组件

//inject the service in constructor
constructor(private service:Service)

ngOnInit() 
    this.username = localStorage.getItem('username');
    this.segment.value = 'FUNCIONAL';
    this.categoria = this.segment.value;
    this.service.getClases(this.categoria).subscribe(res=>
        this.categorias=res
    )

除了某些特殊功能外,您应该避免订阅服务。认为 Angular 是对 Observables 的改造。如果您需要在 Promise 中转换 Observable,这应该是一个很好的理由

【讨论】:

明白了!如果我使用 observables,你能补充一下我怎么做吗?我只想了解如何使用我的服务 Nico,this.http.get 自身返回一个 Observable。在指南中:angular.io/guide/http 你有关于 httpClient 的信息。是的,我们可以使用 'rxjs' "creations" 创建一个 Observable:learnrxjs.io/operators/creation,但 httpClient 方法也返回 Observables,请参阅angular.io/api/common/http/HttpClient。 'rxjs' 的创作,在我们想要的时候是 utils,例如不返回一个值,否则一个可观察的值-使用'of'-,或者当我们想要创建一个计时器时-使用timer-等 很好的解释!谢谢你的时间:)【参考方案2】:

为了获取数据并将其存储在变量中,我能想到的最简洁的解决方案是触发 http 请求 OnInit 生命周期方法并将存储在 Observable 中。

例如:

constructor(private http: HttpClient) 

ngOnInit() 
    this.response$ = this.http.get('http://...');

稍后,您可以使用 toPromise 方法将 response$ 转换为 Promise,并使用 async/await 和它。 另外,如果你多次使用response$要小心,因为它会触发多个http请求,你可以像这样使用shareReplay操作符:

ngOnInit() 
    this.response$ = this.http.get('http://...').pipe(shareReplay(1));

【讨论】:

【参考方案3】:

HttpClient 以角度返回一个 Observable 对象。您可以订阅它,并会给您响应并在多线程上工作。 在这种情况下,您将避免用户等到响应到来。这是一个很好的做法,同时,您可以执行独立于 api 响应数据的其他操作。

但是如果你想等到从 api 获取数据,那么你可以使用 Promise,它可以通过关键字 then 来处理。 在现代 javascript 中,您可以使用 async/await 来处理它。这更像是同步代码,易于阅读和理解。

请关注这里

 ngOnInit() 
    this.username = localStorage.getItem('username');
    this.segment.value = 'FUNCIONAL';
    this.categoria = this.segment.value;
    this.obtenerListadoClases(); 

在 ngOnInit 之前添加异步不是一个好习惯

 async obtenerListadoClases() 
    try 
           this.listadoClases = await this.claseServicio.obtenerListadoClases(this.categoria);
        ).catch((e) => 
           console.log(e);
        );
  

由于 HttpClient 返回一个 5* 角度的 Observable 对象,在这种情况下,您必须使该方法异步,这将返回一个 Promise。你可以按照你曾经做过的方式去做。

return new Promise((resolve, reject) => 
      this.getClases(categoria).subscribe((res: any) => 
                resolve(status: 200, data: res);
            , (error) => 
                resolve(status: 400, data:[]);
            ,
            () => 
                resolve(status: 201, data:[]);
            );
    )

更多信息请查看 Using async-await feature in Angular

【讨论】:

“在 ngOnInit 之前添加 async 不是一个好习惯” - 请解释一下,为什么? 我已经按照你告诉我的那样做了,但是在 console.log 上它仍然显示 undefined ngOnInit() this.obtenerListadoClases(); console.log(this.listadoClases, 'listadoclases'); // 未定义 @mbojko 请看看这个***.com/a/39492163/9739044 @NicoAybar 请像这样导入它import Component, OnInit from '@angular/core'; 并像这样实现它export class YourrComponent implements OnInit @sibabratswain,Observables 是异步的【参考方案4】:
/* On SERVICE */

 getOffice(id: string) 
    return this.firestore.collection('offices').doc(id).valueChanges();
 

/* On COMPONENT */

 ngOnInit(): void 
    let id = this.route.snapshot.params['id'];
    this.service.getOffice(id).subscribe((val) => 
      this.officeDetails = val;
      console.log(this.officeDetails);
    );
 

【讨论】:

以上是关于如何从 ngOnInit Angular 中的服务获取数据的主要内容,如果未能解决你的问题,请参考以下文章

在 Angular 5 中的 ngoninit 之后如何运行函数

在 angular2 中的 ngOnInit 之后,在构造函数中订阅服务

从Angular中的不同本地主机获取数据

组件 ngOnInit 中的 Angular 订阅

Angular5服务调用在ngOnInit上不起作用

Angular`ngOnInit`中的异步/等待