Marcos Santana
Marcos Santana

Reputation: 3

Angular2 - Parent and children communicate via a service

I am trying to make a communication between child components, but by documentation, I need to do this per service, and I am having difficulties when I retrieve the service information, when I try to assign the subscribe return, if I give a console.log(), It works, now if I assign to a variable, it does not consig it accesses it afterwards, giving undefined as an answer.

Daughter class that passes information to another

import { Component, OnInit } from '@angular/core';
import {Angular2TokenService, ResetPasswordData } from 'angular2-token';
import { ActivatedRoute, Router, Params } from '@angular/router';
import { AuthService } from '../services/auth.service';


@Component({
selector: 'app-forgot-passoword',
templateUrl: './forgot-passoword.component.html',
styleUrls: ['./forgot-passoword.component.scss']
})
export class ForgotPassowordComponent implements OnInit {
_resetPasswordData: ResetPasswordData = <ResetPasswordData>{};
tenancy:string;
error:string;
private _sub:any;

constructor(
  private _tokenService: Angular2TokenService,
  private _route: ActivatedRoute,
  private _router: Router,
  private _authService: AuthService
) {}


ngOnInit() {
  this._sub = this._route.parent.params.subscribe(
  params=> this.tenancy = params['tenancy']
  )
}

onSubmit(event){
  event.preventDefault();
  this.error = '';
  this._tokenService.resetPassword({
    email: this._resetPasswordData.email,
  }).subscribe(
    res => {
      console.log(this.tenancy);
      this._authService.confirmResetPassword("check your email");
      this._router.navigate([this.tenancy,'signin'])
   },
    error => this.error = "Error aconteceu algo"
  );

  }

}

Service.

  import { Injectable } from '@angular/core';
  import { ActivatedRoute } from '@angular/router';
  import { Location } from '@angular/common';
  import { Angular2TokenService } from 'angular2-token';
  import { environment } from './../../../environments/environment';
  import { Subject } from 'rxjs/Subject'

  @Injectable()
  export class AuthService {
    tenancy: string;
    private resetPasswordConfirmed = new Subject<string>();
    passwordConfirmed$ = this.resetPasswordConfirmed.asObservable();

    constructor(private _tokenService: Angular2TokenService,
      private activateRoute: ActivatedRoute,
      private _location: Location) { }

    init(){
      this.tenancy = this._location.path().split('/')[1];
      let apiBase:string; 
      if(environment.name==='mock'){
        apiBase = `http://${environment.apiEndPoint}`;
      } else {
        apiBase = `http://${this.tenancy}.${environment.apiEndPoint}`;
      }
      this._tokenService.init({
        apiBase: apiBase
      });
    }

    confirmResetPassword(mensagem: string) {
      this.resetPasswordConfirmed.next(mensagem);
    }
  }

And the other class that will use the service data;

      import { ActivatedRoute, Router } from '@angular/router';
      import { Angular2TokenService, SignInData } from 'angular2-token';
      import { Component, OnInit } from '@angular/core';
      import { AuthService } from '../services/auth.service';
      import { Subscription } from 'rxjs/Subscription'


      @Component({
        selector: 'app-signin',
        templateUrl: './signin.component.html',
        styleUrls: ['./signin.component.scss']
      })
      export class SigninComponent implements OnInit {
        private _signInData: SignInData = <SignInData>{};
        tenancy:string;
        error:string;
        resetPasswordSucess:string;
        _sub: any;
        subscription: Subscription;

        constructor(
          private _tokenService: Angular2TokenService,
          private _route: ActivatedRoute,
          private _router: Router,
          private _authService: AuthService
        ){   
          this.subscription= _authService.passwordConfirmed$.subscribe(
              mensagem =>{ 
                this.resetPasswordSucess = mensagem;
                console.log(mensagem + '  Mensagem');
              }      
            ); 

        }
        ngOnInit() {
          this._sub = this._route.parent.params.subscribe(
            params=> this.tenancy = params['tenancy']
          );
        }

        onSubmit(){

          this.error = '';
          this._tokenService.signIn(this._signInData)
            .subscribe(
              res   => console.log("DEU CERTO"),
              error => console.log(error)
            );

        }
      }

If execute console.log(this.resetPasswordSucess) outside of subscribe, value the variable is UNDEFINED.

How to assign the value in the variable and that everyone can see outside the subscribe?

Upvotes: 0

Views: 756

Answers (2)

Tyler Jennings
Tyler Jennings

Reputation: 8911

It is likely that when your ForgotPasswordComponent calls

this._authService.confirmResetPassword("check your email");

that your SignInComponent has not yet subscribed to the _authService.passwordConfirmed$ in your service.

Instead of using private resetPasswordConfirmed = new Subject<string>(); in your AuthService try using private resetPasswordConfirmed = new BehaviorSubject<string>(''); or private resetPasswordConfirmed = new ReplaySubject<string>();

The difference is a Subject is a fire and forget. If the subscriber hasn't subscribed to the observable by the time it fires then it misses the value. A ReplaySubject will replay past values when a new subscriber subscribes. Likewise a BehaviorSubject will provide the latest value upon subscription even if the next value hasn't been received.

From http://reactivex.io/documentation/subject.html

Behavior Subject: When an observer subscribes to a BehaviorSubject, it begins by emitting the item most recently emitted by the source Observable (or a seed/default value if none has yet been emitted) and then continues to emit any other items emitted later by the source Observable(s).

ReplaySubject: emits to any observer all of the items that were emitted by the source Observable(s), regardless of when the observer subscribes.

Hope that helps.

Upvotes: 1

Aleksandr Petrovskij
Aleksandr Petrovskij

Reputation: 1243

resetPasswordSucess property will be set only after first output from passwordConfirmed$

Upvotes: 0

Related Questions