[英]Angular2 - OnInit : Values returned from Service' subscribe function does not get assigned to Component field/s
I'm trying out Angular2 and have been following their tutorials.我正在尝试 Angular2 并一直在关注他们的教程。
I currently have a Service that gets data from a json server:我目前有一个从 json 服务器获取数据的服务:
import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { User } from './user';
@Injectable()
export class UserService {
constructor(private http: Http) {}
private usersUrl = 'http://localhost:3000/users';
getUsers(): Observable<User[]> {
return this.http.get(this.usersUrl) //the request won't go out until something subscribes to the observable
.map(this.extractData)
.catch(this.handleError); // pass an error message back to the component for presentation to the user but only if we can say something the user can understand and act upon
}
private extractData(response: Response) {
if (response.status < 200 || response.status >= 300) {
throw new Error('Bad response status: ' + response.status);
}
let body = response.json(); // parse JSON string into JavaScript objects
return body.data || { };
}
private handleError (error: any) {
// In a real world app, we might send the error to remote logging infrastructure before returning/sending the error
let errMsg = error.message || 'Server error'; // transform the error into a user-friendly message
return Observable.throw(errMsg); // returns the message in a new, failed observable
}
}
And my Component:还有我的组件:
import { Component, OnInit } from '@angular/core';
import { User } from '../common/user/user';
import { UserService } from '../common/user/user.service';
@Component({
selector: 'app-nav',
templateUrl: '/app/nav/nav.component.html',
styleUrls: ['/app/nav/nav.component.css']
})
export class NavComponent implements OnInit {
errorMsg: string;
users: User[];
constructor(private userService: UserService) { }
getUsers() {
this.userService
.getUsers()
.subscribe(
function(users) {
console.log('users ' + users);
this.users = users;
console.log('this.users ' + this.users);
}, function(error) {
console.log('error ' + error);
});
// users => this.users = users,
// error => this.errorMsg = <any>error);
}
ngOnInit() {
this.getUsers();
console.log('ngOnit after getUsers() ' + this.users);
}
}
My problem is, the data returned from the subscribed function is not being passed/assigned to my Component property 'users' after the getUsers() invocation completes.我的问题是,在 getUsers() 调用完成后,从订阅函数返回的数据没有传递/分配给我的组件属性“用户”。 I do know that the data is returned to the component from the service method call because I'm able to log the data within the userService().getUsers method.
我确实知道数据从服务方法调用返回到组件,因为我能够在 userService().getUsers 方法中记录数据。 The weird thing is, the console.log invocation on my ngOnInit is being printed on my dev console first before the console.logs within my getUsers method, although I invoke the getUsers first:
奇怪的是,我的 ngOnInit 上的 console.log 调用首先在我的 getUsers 方法中的 console.logs 之前打印在我的开发控制台上,尽管我首先调用了 getUsers:
ngOnInit() {
this.getUsers();
console.log('ngOnit after getUsers() ' + this.users);
}
Dev console screenshot:开发控制台截图:
This is because this.getUsers()
and then this.userService.getUsers().subscribe(...)
only schedules a call to make a request to the server.这是因为
this.userService.getUsers().subscribe(...)
this.getUsers()
和this.userService.getUsers().subscribe(...)
只安排调用向服务器发出请求。 Eventually when the response from the server arrives ( console.log('ngOnit after getUsers() ' + this.users);
was already executed before the call to the server was even made) then the function you passed to subscribe()
is executed.最终当来自服务器的响应到达时(
console.log('ngOnit after getUsers() ' + this.users);
在调用服务器之前已经执行了)然后你传递给subscribe()
的函数被执行.
This should do what you want:这应该做你想做的:
getUsers() {
return this.userService
.getUsers()
.map(
(users) => {
console.log('users ' + users);
this.users = users;
console.log('this.users ' + this.users);
})
.catch((error) => {
console.log('error ' + error);
throw error;
});
// users => this.users = users,
// error => this.errorMsg = <any>error);
}
ngOnInit() {
this.getUsers().subscribe(_ => {;
console.log('ngOnit after getUsers() ' + this.users);
});
}
In getUsers()
I use map()
instead of subscribe, so we can subscribe later in order to be able to get code executed when the response arrived.在
getUsers()
我使用map()
而不是 subscribe,因此我们可以稍后订阅,以便能够在响应到达时执行代码。
Then in ngOnInit()
we use the subscribe()
( subscribe()
is necessary, otherwise would http.get()
would never be executed) and pass the code we want to be executed when the response arrives.然后在
ngOnInit()
我们使用subscribe()
( subscribe()
是必要的,否则http.get()
将永远不会被执行)并在响应到达时传递我们想要执行的代码。
I also changed function ()
to () =>
.我还将
function ()
更改为() =>
。 This way this
works inside the following code block () => { ... }
, otherwise it wouldn't.这样
this
可以在下面的代码块() => { ... }
,否则就不会。
Don't forget to add不要忘记添加
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
otherwise these operators won't be recoginzed.否则这些运算符将不会被识别。
for me this is works like magic i was need to get data from api to initialize datatable component对我来说,这就像魔术一样,我需要从 api 获取数据来初始化数据表组件
1- on your http service create normal get request like this : 1- 在您的 http 服务上创建正常的 get 请求,如下所示:
public get(url: string):Observable<any> {
return this.http.get<any>( url );
}
2- on your component : 2- 在您的组件上:
constructor(private HttpSvc: HttpService) {}
ngOnInit() {
this.render();
}
render() {
let options = this.options || {};
this.HttpSvc.Get('your api url').subscribe(data => {
this.Tableset = data;
options = {
data: this.Tableset.data,
columns: this.Tableset.columns,
dom: 'Bfrtip',
buttons: this.Tableset.buttons,
autoWidth: false,
pageLength: 2,
retrieve: true,
responsive: true
};
}, err => {console.log(err); },
() => {
this.renderDetails(options); //<-- can call any other method after call end
});
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.