повторно использовать одну тему rxjs для нескольких функций - PullRequest
0 голосов
/ 10 мая 2018

У меня есть ApiClientService, который получает rxjs Service в качестве одного из параметров во всех его методах. Затем эта служба будет вызывать API, subscribe для возвращенных Observable s, анализировать возвращаемые значения и затем вызывать обратный вызов Subject next().

Эта модель работает нормально, пока в одном из классов, скажем, UserService, у меня не будет одного Subject, который используется для вызова нескольких API. Этот Subject обратный вызов *1011* не вызывается при возврате второго 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();
    }

}

1 Ответ

0 голосов
/ 10 мая 2018

Я не вижу причину проблемы, но я могу попытаться дать вам несколько советов.

Зачем использовать тему?

Почему бы вам напрямую не вернуть свой компонент Observable, возвращаемый http-клиентом, возможно, преобразованный с помощью оператора 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;
}

тогда вы просто подпишетесь на Observable, возвращаемый методом sessionLogin или userLogin.

Автоматический вход в систему ngOnInit ()

Это часть вашего метода 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. Это не ясно: если пользователь вошел в систему, вам не нужно звонить

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...