如何从 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 之后如何运行函数