在多个函数中重用一个rxjs'主题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在多个函数中重用一个rxjs'主题相关的知识,希望对你有一定的参考价值。
我有一个ApiClientService
接收rxjs Service
作为其所有方法中的参数之一。然后,此服务将API,subscribe
调用返回的Observable
s,解析返回值,然后回调Subject
的next()
回调。
这个模型工作正常,直到在其中一个类中,让我们说UserService
,我有一个用于调用多个API的Subject
。这个Subject
的next()
回调不会在第二个API返回时被调用。我已经确认API确实返回了,它确实调用了Service.next()
,传递了所需的值。
这是预期的行为吗? (每个Observable
服务一次)或者我的设计有问题吗?
提前致谢!
// ApiClientService.ts
@Injectable()
export class ApiClientService {
postUserLogin(userid: string, password: string): Observable<Object> {
const url = "/api/getforuser";
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
})
}
return this.http.post(url, { userid: userid }, httpOptions);
}
postSessionLogin(sessionid: string): Observable<Object> {
const url = "/api/getforsession";
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
})
}
return this.http.post(url, { sessionid: sessionid }, httpOptions);
}
}
UserService.ts
// UserService.ts
@Injectable()
export class UserService {
currentUser: UserModel;
constructor(
private apiclient: ApiClientService
) { }
isLoggedIn(): boolean {
if ( this.currentUser == null ) {
return false;
} else if ( this.currentUser.session != null ) {
if ( this.currentUser.session.length > 0 ) {
return true;
}
}
return false;
}
sessionLogin(userListener: Subject<UserModel>) {
console.log("UserService.sessionLogin");
var session = this.cookieService.get("session");
if ( session == null ) {
userListener.error("session not found");
} else {
var obRes = this.apiclient.postSessionLogin(session);
obRes.subscribe( res => {
console.log("sessionLogin response");
var payload = res['payload'];
console.log("payload: " + payload);
var user = payload['user'];
console.log("user: " + user);
this.currentUser = new UserModel;
this.currentUser.userid = user.userid;
userListener.next(this.currentUser);
});
}
}
userLogin(username: string, password: string, userListener: Subject<UserModel>) {
console.log("UserService.userLogin start");
var obRes = this.apiclient.postUserLogin(username, password);
obRes.subscribe( res => {
console.log("UserService.userLogin response start...");
console.log(res);
console.log("userLogin response json...");
var payload = res['payload'];
console.log("payload: " + payload);
var user = payload['user'];
console.log("UserService.userLogin user: " + user);
this.currentUser = new UserModel;
this.currentUser.userid = user.userid;
userListener.next(this.currentUser);
}, err => {
console.log("not even error, nothing...");
console.log(err);
});
}
}
使用UserService
的前端组件
// UserLoginComponent
@Component({
selector: 'app-home-login',
templateUrl: './home-login.component.html',
styleUrls: ['./home-login.component.scss']
})
export class HomeLoginComponent implements OnInit {
@Input() userModel: UserModel;
loggedinUser: UserModel;
userloginForm: FormGroup;
// it doesn't work if it is only 1 Subject (loginListener) used for both userLogin and sessionLogin
loginListener: Subject<UserModel>;
loginListenerSubs: Subscription;
// it will work if I have another Subject (sessionListener) which is used separately for sessionLogin
// sessionListener: Subject<UserModel>;
// sessionListenerSubs: Subscription
constructor(private fb: FormBuilder,
private router: Router,
private userService: UserService
) {
this.createForm();
}
createForm() {
this.userloginForm = this.fb.group({
username: [ '', Validators.required ],
password: [ '', Validators.required ]
});
}
onSubmitLogin() {
this.userModel = this.pullFormContent();
this.userService.userLogin(this.userModel.username, this.userModel.password, this.loginListener);
// same result if it is placed here as well
// this.loginListenerSubs = this.loginListener.subscribe(
// user => this.onLoginSuccess(user),
// error => this.onLoginFailed(error),
// () => this.onLoginCompleted()
// );
}
pullFormContent() {
const formModel = this.userloginForm.value;
console.log("home-login component: pullformContent formModel");
console.log(formModel);
const user: UserModel = {
userid: 0,
username: formModel.username,
password: formModel.password,
}
return user;
}
onLoginSuccess(user) {
console.log("loginListener next"); // never get called the second api call
console.log(user);
this.loggedinUser = user;
console.log(this.loggedinUser);
if ( this.router == null ) {
console.log("router is null");
} else {
this.router.navigate(['/some/user/view']);
}
}
onLoginFailed(error) {
console.log("loginListener error: " + error);
}
onLoginCompleted() {
console.log("loginListener complete");
}
ngOnInit() {
console.log("home-login-component ngOnInit");
this.loginListener = new Subject<UserModel>();
this.loginListenerSubs = this.loginListener.subscribe(
user => this.onLoginSuccess(user),
error => this.onLoginFailed(error),
() => this.onLoginCompleted()
);
// try to login automatically
this.userService.sessionLogin(this.loginListener);
if ( this.userService.isLoggedIn() ) {
console.log("user is logged in, todo: auto redirect");
this.router.navigate(['/some/user/view']);
}
}
ngOnDestroy() {
console.log("ngOnDestroy");
this.loginListenerSubs.unsubscribe();
}
}
答案
我看不出问题的原因,但我可能会试着给你一些建议。
为何使用主题?
你为什么不直接返回你的组件http客户端返回的Observable,可能通过map
运算符转换?例如,这意味着这样的事情
sessionLogin() {
console.log("UserService.sessionLogin");
var session = this.cookieService.get("session");
if ( session == null ) {
Observable.throw("session not found");
} else {
return this.apiclient.postSessionLogin(session)
.map( res => {
console.log("sessionLogin response");
return this.buildUser(res);
});
}
}
userLogin(username: string, password: string) {
console.log("UserService.userLogin start");
return this.apiclient.postUserLogin(username, password)
.map( res => {
console.log("UserService.userLogin response start...");
console.log(res);
console.log("userLogin response json...");
return this.buildUser(res);
};
}
buildUser(res) {
const payload = res['payload'];
console.log("payload: " + payload);
const user = payload['user'];
console.log("UserService.userLogin user: " + user);
this.currentUser = new UserModel;
this.currentUser.userid = user.userid;
return this.currentUser;
}
然后,您只需订阅sessionLogin或userLogin方法返回的Observable。
自动登录
这是你的ngOnInit()方法的一部分
// try to login automatically
this.userService.sessionLogin(this.loginListener);
if ( this.userService.isLoggedIn() ) {
console.log("user is logged in, todo: auto redirect");
this.router.navigate(['/some/user/view']);
}
您正在调用sessionLogin
并立即检查是否有用户使用isLoggedIn
方法登录。目前尚不清楚:如果用户已登录,则无需致电
以上是关于在多个函数中重用一个rxjs'主题的主要内容,如果未能解决你的问题,请参考以下文章