2

I am trying to use an Observable/Behaviour subject in the following way: I have a component which is displayed everywhere in the app as a background. In a form-component that shows over that background I want to take data that comes from the user and to use this data to make an asynchronous call, and to use the result of that asynchronous call a method in that background component
So in my app.component.ts I have

<app-header></app-header>
 <backround-component></background-component>
 <router-outlet></router-outlet>

ln In my my app.routing.ts I have:

const appRoutes: Routes = [
  { path: '',
    redirectTo: 'home', 
    pathMatch: 'full'},
  { path: 'home', component: HomeComponent },
  { path: 'form-component', component: Form component where the user submits the data }, 
];

In the form-component.html I have:

<button class="btn--submit" (click)="onClick()">Click</button>

So what I am trying to do is:

1) On data submission in the form-component call a method from the service that builds the request based on the submitted data:

onClick = function() {
    this.service.makeAsynchCall(dataFromTheUser);
}

2) Make asynchronous call to remote API:

public makeAsynchCall(dataFromTheUser): Observable<any> {
    // build the request based on the data
    return Observable.create((observer) => {
        this.someRemoteService.route(request, (response, status) => {
            observer.next(response);
        });
    });
}

3) Subscribe to that observable in the background-component in a ngBeforeView lifecycle hook so that I can use the response:

ngBeforeView {
    this.service.makeAsynchcall().subscribe(response =>
        this.useTheResponse(response);
    );
}

What I suppose that is happening is that on loading of that background component the asynch call first is forcefully invoked, then it forcefully invokes the method that expects data from the user, the data is not submitted yet and the request fails. I also tried another scenario - using BehaviourSubject / AsyncSubject as a connecting piece exploiting its role of both observer and Observable and make it notify other subscribers when the data has arrived and that didn’t work too. Thank you in advance for your help.

Update: tried the following based on the example in the answer below

Here is what I tried to do. In my subscriber, the next() method just prints the value received. Everything else is the same (except I didn't create the data model)

public update(data)
{
    let request = {}; // build request object based on 'data'   

    this.source.next(data); // subscriber doesn't get the value (not printed)

    // make async call
    this.service.asyncCall(request, (response, status) => {
        if (status == OK) {
            console.log('got result'); // this prints, so we get here
            this.source.next(data); // subscriber doesn't get the value (not printed)
        }
    });
}
tomcat
  • 43
  • 8

1 Answers1

2

Hey I made you and example in how to share data between multiple components by making an observable service:

import {ReplaySubject, Subscription} from "rxjs";

export class DataModel
{
    constructor(public valueOne: string,
                public valueTwo: string)
    {

    }
}

export class FormComponent
{

    constructor(private shareService: ShareService)
    {
    }

    onFormSubmit(formData: DataModel)
    {
        const newData = new DataModel(formData.valueOne, formData.valueTwo)
        this.shareService.update(newData);
    }

}
export class ShareService
{
    private source = new ReplaySubject<DataModel>();
    public source$ = this.source.asObservable();

    public update(data)
    {
        this.source.next(data)
    }
}


export class BackGroundComponet
{
    private subscription: Subscription;
    private data: DataModel;

    constructor(private shareService: ShareService)
    {
        this.subscription = this.shareService
            .source$
            .subscribe(data =>
            {
                this.data = data; //assign new data to class member
                this.onShareServiceUpdated(); //call some method to do something with it
            });
    }

    private onShareServiceUpdated()
    {
        //Make api call with new data
        console.log(this.data);
    }
}
rtn
  • 2,012
  • 4
  • 21
  • 39
  • Hello and thanks a lot for your help. I tried what you suggested, and it works fine till the moment the subscriber should take the value from the source. Do you, by any chance, know why the subscriber can't get the result from the source? I have updated my question using what I've got so far. Thanks! – tomcat Dec 03 '16 at 12:32
  • Take a look at this question regarding the nwe issue of subscribers not getting notified of the changes: https://stackoverflow.com/questions/37150891/issue-with-rxjs-behaviorsubjects-subscriber-not-being-notified-of-value-change – Filkolev Dec 03 '16 at 12:43