有关Angular 5可观察对象的帮助。
我想对控制器隐藏复杂性;那就是不必让它必须订阅可观察的东西。具有服务的所有复杂性,并使其简单地将结果/有效载荷返回给组件。但显然我陷入了时间问题。我觉得这应该是一个热门的话题,但是还没有找到答案。所以也许我要去做错事了?
//in the component.ts
const allColors = this.auth.getColors(); //service call
console.log(allColors); // returns undefined
//in the service.ts
getColors() {
var myColors = "";
var colors = this.http.get<any>('http://localhost/Account/GetColors', httpOptions)
.pipe(catchError(this.handleError));
//
colors.subscribe(
res => {
myColors = res.body;
},
error => {}
);
return myColors;
}
答案 0 :(得分:4)
我认为您无法做您想做的事情,因为在服务中的订阅未解决之前,它不会向组件发送任何内容,在组件的执行中,它是未定义的,因为响应尚未得到响应。还没来。
这就是发明回调函数的原因。正确的方法是在要等待服务响应的组件中添加订阅。
对不起,但是我还不能使用评论,所以我不得不做出回复。希望对您有帮助
答案 1 :(得分:2)
所以也许我要去做错事了?
的确。使用Observable和Promises进行异步编程。我认为这是您提出此问题的唯一原因,您不完全了解它们的工作原理,因此您想将其抽象化,这是您无法做到的。另请参见How do I return the response from an asynchronous call?
也就是说,您可以使用async/await来提供同步代码的外观。
component.ts
async ngOnInit() {
const allColors = await this.auth.getColorsAsync(); //service call
console.log(allColors); // returns color array
}
service.ts
getColorsAsync(): Promise<color[]> {
return this.http.get<color[]>('http://localhost/Account/GetColors', httpOptions)
.pipe(catchError(this.handleError))
.toPromise();
}
我猜到了实际类型。理想情况下,应该在所有可能的情况下使用强类型
答案 2 :(得分:1)
您的方法何时返回?这就是您需要回答的问题,为了避免您的悬念,它将使 prior 返回myColors中充满了任何东西的东西,这就是异步编程的本质。
您需要返回可观察的对象,并在结果可用时让它通知。这种复杂性无法用您尝试的方式隐藏起来,最接近的方法是将回调函数传递到服务方法中,然后在有可用结果时调用该方法,如下所示:
getColors(callback) {
//...
colors.subscribe(
res => {
callback(res.body);
}
//...
);
}
但是随后您将错过许多很酷的功能,例如能够将multiple subscribers设置为相同的可观察对象。
答案 3 :(得分:1)
您要使用Resolver
并在使用服务之前路由到预加载数据。
解析器是一种异步操作,在激活其余路由之前已完成。因此,您将定义一个顶级路由,该路由不执行任何操作,但包含用于获取颜色数据的解析器。我说顶层是因为我假设这是全局应用程序数据。如果此数据是特定于功能的,则将解析器放置在正确的路由路径中。
const routes: Routes = [
{
path: '',
resolve: {
Colors: ColorsResolver
},
children: [
// your application routes here
]
}
]
类ColorsResolver
将从服务器获取颜色数据,然后将其分配给服务。
@Injectable()
export class ColorsResolver implements Resolve<any> {
public constructor(private colorService: ColorService) {}
public resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> {
return this.http.get<any>('http://localhost/Account/GetColors', httpOptions)
.do((resp)=> this.colorService.setColor(resp));;
}
}
在服务中,您只需将值分配给属性
@Injectable()
public ColorService {
public setColor(resp: any) { this._color = resp; }
public getColor():any { return this._color; }
}
您现在可以在解析器完成操作后多次调用getColor()
,而不会阻塞它。
答案 4 :(得分:0)
与Osakr所说的不符。您将必须订阅您的组件。
在您的service.ts中
getColors(): Observable<any> {
let urlString = 'http://localhost/Account/GetColors'
return this.http.get(urlString);
}
在您的组件中:
getColors() {
this.service.getColors()
.subscribe((colors) => {
this.myColors = colors;
})
}
答案 5 :(得分:0)
我认为您可以以其他方式做到
//in the component.ts
this.service.getColors(); //service call
console.log(this.service.allColors); // print the service property. which will resolve after the oberservable resolve
//in the service.ts
@injectable()
export class Service {
public allColors: any; //Public property to print.
public getColors() {
var myColors = "";
var colors = this.http.get<any>('http://localhost/Account/GetColors', httpOptions)
.pipe(catchError(this.handleError));
colors.subscribe(
res => {
this.allColors= res.body;
},
error => {}
);
return;
}
}
答案 6 :(得分:0)
这是我要怎么做:
this.http.get<any>('http://localhost/Account/GetColors', httpOptions)
.pipe(catchError(this.handleError))
.subscribe(res => {
console.log(res.body);
});