57

In component :

singleEvent$: Observable<Event>;

On init, I get observable

this.singleEvent$ = this._eventService.events$
  .map(function (events) {
    let eventObject = events.find(item => item.id === eventid);
    let eventClass: Event = new Event(eventObject);
    return eventClass;
  });

How can I take current value like event.name ?

IAmInPLS
  • 4,051
  • 4
  • 24
  • 57
SuperOrange
  • 673
  • 1
  • 5
  • 5

6 Answers6

99

To get data from an observable, you need to subscribe:

this.singleEvents$.subscribe(event => this.event = event);

In the template you can directly bind to observables using the async pipe:

{{singleEvents$ | async}}
frido
  • 13,065
  • 5
  • 42
  • 56
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • My subscriber in service But i need take name in component – SuperOrange Jun 03 '16 at 10:41
  • 23
    Sorry, I can't make any sense from your comment. – Günter Zöchbauer Jun 03 '16 at 10:44
  • 1
    I think he means that in the service he uses .subscribe and then have a subject (or similar) that the component uses. let´s say that there is a page component that have a child that takes an async input. then the parent component needs some data for other requests? – Mackelito Sep 11 '17 at 13:11
  • 1
    @Mackelito sorry, but that doesn't make it more clear. If this is actually a question that bothers you, then I'd suggest to create a new question that includes the code that demonstrates what you try to accomplish. – Günter Zöchbauer Sep 11 '17 at 13:15
  • 1
    I believe what he is missing is that he needs to use .subscribe in the component as well. :) – Mackelito Sep 11 '17 at 13:23
15

To add on to Günter Zöbauer's answer, a BehaviorSubject may be what you are looking for if you're looking to synchronously get the value inside of your Observable.

A BehaviorSubject is an Observable that always has a value, and you can call myBehaviorSubject.getValue() or myBehaviorSubject.value to synchronously retrieve the value the BehaviorSubject currently holds.

Since it is itself an observable as well, you can still subscribe to the BehaviorSubject to asynchronously react to changes in the value that it holds (e.g. myBehaviorSubject.subscribe(event => { this.event = event })) and use the async pipe in your component's template (e.g. {{ myBehaviorSubject | async }}).

Here's some usage to match your given example to create a BehaviorSubject in your component from the given service:

@Component({
  //...
})
export class YourComponent implements OnInit {
  singleEvent$: BehaviorSubject<Event>;

  constructor(private eventService: EventService){}

  ngOnInit(){
    const eventid = 'id'; // <-- actual id could go here
    this.eventService.events$
      .pipe(
        map(events => {
          let eventObject = events.find(item => item.id === eventid);
          let eventClass: Event = new Event(eventObject);
          return eventClass;
        })
      )
      .subscribe(event => {
        if(!this.singleEvent$){
          this.singleEvent$ = new BehaviorSubject(event);
        } else {
          this.singleEvent$.next(event);
        }
      });
  }
}
ZackDeRose
  • 2,146
  • 1
  • 16
  • 28
  • What I want is an observable that I can observe without subscribing, and without using BehaviorSubject, since you can modify it with next() – Narvalex Sep 13 '18 at 13:46
  • 3
    recently been really liking the async/await API for similar use-cases that might be of interest @Narvalex. The idea is you use it like so: `const foo = await obs$.pipe(take(1)).toPromise()` inside of an asynchronous function. – ZackDeRose Dec 01 '18 at 22:03
  • Thanks for the tip men. This was indeed an interview question about the difference between a Subject and BehaviourSubject and it is all clear to me now. – Arnold Layne Jan 10 '19 at 10:43
  • 2
    Isn't it risky to expose `BehaviorSubject` on your components?! What's the point of using `Observable` (cloning) if you are just exposing the `BehaviorSubject`? – Elysiumplain Feb 25 '19 at 20:55
10

You can use observable.pipe(take(1)).subscribe to limit the observable to get only one value and stop listening for more.

let firstName: string; 

        this.insureFirstName
            .pipe(take(1))  //this will limit the observable to only one value
            .subscribe((firstName: string) => {
                this.firstName = firstName; asssgning value 
            });
        console.log(this.firstName); //accessing the value
rmcsharry
  • 5,363
  • 6
  • 65
  • 108
1

If you need the value of an observable at a specific point in time I would convert it to a Promise and await for it like so:

import { firstValueFrom } from 'rxjs';

const value = await firstValueFrom(obs$);

The Observable would resolve immediately if it is an BehaviorSubject under the hood.

Dom
  • 333
  • 2
  • 5
0

Adding to what @ZackDeRose was adding on @Günter Zöchbauer response

private beneficiary = new BehaviorSubject<__IBeneficiary>(newBeneficiary);
beneficiary$ = this.beneficiary.asObservable();

setBeneficiaryInfo(beneficiary: __IBeneficiary): void {
    this.beneficiary.next(beneficiary);
    // when your you subscribe to beneficiary$ you would get the new value
}

/* when implementing in component or other function
   this.beneficiary$.subscribe(
        item => {
            // use current value
        }
    );
*/

modePersonalInformation(personalInfo, mode: string): Observable<any> {
    const $beneficiary = this.beneficiary.value; 
    // this will get the current observable value without the subscrib callback function
    return this.http.post<any>(
        `${this.apiURL}/${mode}-biography/personal` + ((mode === 'update' && $beneficiary?.id) ? `/${$beneficiary.id}` : ''),
        {...personalInfo},
        this.httpOptions
    )
}

you would have to put some conditionals to check if you want to use an existing object or not

0

I hate to say it, but these are all wrong answers. You can easily get the value if it exists by using,

this._eventService.events$.source['_value'] 

And get any value you want from the object. The source is deprecated but still works.

tdy
  • 36,675
  • 19
  • 86
  • 83
Pooria Shahin
  • 59
  • 1
  • 4