简体   繁体   English

Angular 5将服务注入组件

[英]Angular 5 injecting services into components

I have an issue with my authentication service + component in that the service seems to be reinitialized every time I load up the auth component. 我的身份验证服务+组件存在问题,因为每次加载auth组件时,该服务似乎都会重新初始化。 The flow that should be present in my app is that the root app-component should, upon the application starting, send a log in request to check if the current session is authenticated or not. 我的应用程序中应该存在的流程是,根应用程序组件应在应用程序启动时发送登录请求,以检查当前会话是否已通过身份验证。 This login request is being sent from the auth-service. 此登录请求是从auth-service发送的。 The auth-service has a subject broadcasting a boolean indicating if the user is authenticated or not, depending on the result of the login/logout operation. auth-service的主题广播一个布尔值,该布尔值指示用户是否通过身份验证,具体取决于登录/注销操作的结果。

This works great except for one scenario. 除一种情况外,这非常有用。 If I start the app on the auth page, navigate away from the component and go back to it, I cannot get the proper authentication status (true/false) from the service. 如果我在身份验证页面上启动该应用程序,请离开该组件并返回到该组件,则无法从该服务获得正确的身份验证状态(真/假)。 The field (in the service) when printed states undefined for some reason. 由于某些原因,打印时的字段(服务中)状态未定义。 To debug, I have even inserted console.logs in the ngOnInit functions to see if any of the components/services were being reinitialized, but nothing. 为了调试,我什至在ngOnInit函数中插入了console.logs来查看是否有任何组件/服务被重新初始化,但是什么也没有。

Here is a code sample of how it looks right now, app.component.ts (root component): 以下是app.component.ts (根组件)的外观示例代码:

constructor(private requestService: RequestService,
              private authService: AuthService) {}

  ngOnInit() {
    console.log("App component init");
    this.requestService.get('http://localhost:8000/api/csrf/')
      .subscribe(
        success => {
          this.authService.login('', '');
        }
    );
  }

The login request is fired as a result of the first CSRF check, this works well so far. 第一次CSRF检查的结果是触发了登录请求,到目前为止效果良好。

auth.service.ts

@Injectable()
export class AuthService implements OnInit, OnDestroy {
  authenticated: boolean;
  authSubject: Subject<boolean>;

  constructor(private requestService: RequestService) {
    console.log("Auth service constructor");
    this.authSubject = new Subject<boolean>();
  }

  ngOnInit() {
    console.log("Auth service init");
    this.authSubject.subscribe(
      next => {
        this.authenticated = next;
      }
    );
  }

  login(username: string, password: string) {
    console.log("Auth service login");
    this.requestService.post(LOGIN_URL, { username: username, password: password })
      .subscribe(
        next => {
          this.authSubject.next(true);
          console.log("[AuthService] Success logging in.");
        },
        error => {
          console.log("[AuthService] Error logging in.");
        },
        () => {
          console.log("[AuthService] Auth service completed.");
        }
      );
  }

  logout() {
    this.requestService.post(LOGOUT_URL, {})
    .subscribe(
      next => {
        this.authSubject.next(false);
        console.log('[AuthService] Success logging out.');
      },
      error => {
        console.log("[AuthService] Error logging out.");
      },
      () => {
        console.log("[AuthService] Auth service completed.");
      });
  }

  isAuthenticated(): boolean {
    return this.authenticated;
  }

  ngOnDestroy() {
    console.log("Auth service destroyed");
    this.authSubject.unsubscribe();
  }
}

Here we go, as you can see above, I have resorted to instantiating the Subject in the constructor rather than in ngOnInit. 正如上面您所看到的,我们开始了这里的工作,我不得不在构造函数而不是ngOnInit中实例化Subject。 This is because when the login is fired from app.component.ts the subject has not yet been created which causes a crash. 这是因为从app.component.ts触发登录时,尚未创建主题,这会导致崩溃。 This still works though. 虽然这仍然有效。

auth.component.ts

export class AuthComponent implements OnInit {
  authenticated: boolean;

  constructor(private authService: AuthService) { }

  ngOnInit() {
    console.log("Auth component init");
    this.authService.authSubject.subscribe(
      next => {
        this.authenticated = next;
      }
    );
    this.authenticated = this.authService.isAuthenticated();
    console.log(this.authenticated);
  }

  onLogin(form: NgForm) {
    const username = form.value.username;
    const password = form.value.password;
    this.authService.login(username, password);
  }

  onLogout() {
    this.authService.logout();
  }

So, here is where I am stuck. 所以,这就是我被困住的地方。 When I login, see that I successfully get a response and that authenticated = true. 登录时,看到我已成功获得响应,并且authenticated = true。 However, when I navigate away from the auth view and then back to it, getting the authenticated value from authService.isAuthenticated gives me back "undefined"! 但是,当我离开auth视图并返回到该视图时,从authService.isAuthenticated获取身份验证的值使我回到“未定义”状态! The service is there and intact (I tapped into the ngOnDestroy for the service, nothing is fired there) so I am guessing there is a reference problem or something, I just can't find anything in the documentation to help me out. 该服务在那里并且完好无损(我进入ngOnDestroy进行该服务,那里什么也没有触发),所以我猜测存在参考问题或其他问题,我只是在文档中找不到任何可以帮助我的东西。

Please advise. 请指教。

Try to use a BehaviorSubject instead of just a Subject . 尝试使用BehaviorSubject而不是Subject A BehaviorSubject will broadcast out the last value before subscription plus any new values whereas a subject will only broadcast out any new data after you subscribe. BehaviorSubject将播出订阅前的最后一个值以及任何新值,而主题只会在您订阅后播出任何新数据。

What is the difference between Subject and BehaviorSubject? Subject和BehaviorSubject有什么区别?

The problem lied in that ngOnInit is not called for angular services, so the subscription was never activated in the auth service. 问题在于ngOnInit没有为角度服务调用,因此该订阅从未在auth服务中激活。 When I moved the subscription to the services constructor it all works! 当我将预订移到服务构造函数时,所有工作都成功了!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM