user12425844
user12425844

Reputation:

Get Last Value from Observable in Angular 8

How do I get the last value from an Observable in Angular 8?

let test = new BehaviorSubject<any>('');
test.next(this.AddressObservable);

let lastValue = test.subscribe(data=>console.log(data.value));

For some reason it is not working, checking debugger.

However, this is working in html, AddressObservable | async

Trying to utilize this link, want to store value in variable or display in console log. Any newer syntax would be helpful .

How to get last value when subscribing to an Observable?

Note:

AddressObservable is of type: Observable<AddressDto>

Upvotes: 5

Views: 23733

Answers (2)

Kurt Hamilton
Kurt Hamilton

Reputation: 13515

Judging by the question, there seems to be confusion with the BehaviorSubject and what it does.

A Subject is effectively a stream of values from some source that you can subscribe to. Whenever a new value is emitted, it arrives in the subscribe method.

If you have an initial state, you can use a BehaviorSubject to initialise the subject and ensure new subscribers always receive a value.

If you don't have an initial state, but want to ensure new subscribers get the last emitted value on subscribing—if one exists—then you can use ReplaySubject.

All of the values that go into a Subject are of type T, where you have Subject<T>. Therefore, in your case, everything going into the Subject should be an AddressDto.

If you have an initial address, then you would set up your BehaviorSubject as follows.

// Somehow get the initial address.
const address = new AddressDto();
const test = new BehaviorSubject<AddressDto>(address);

// All subscribers will receive this address on subscribing.

// Something happens.

// There is another address; emit that.
const newAddress = new AddressDto();
test.next(newAddress);

// All new subscribers will receive newAddress on subscribing.

On the other hand, if you don't have an initial address you can use a ReplaySubject as demonstrated below.

// Always emit the last address to new subscribers by intitialising it with the number 1.

// New subscribers won't receive an address until one is emitted.
const test = new ReplaySubject<AddressDto>(1);

// Something happens.

// Get the first address, and emit it.
const firstAddress = new AddressDto();
test.next(firstAddress);

// All current subscribers receive firstAddress.

// All future subscribers will receive firstAddress on subscribing

// Something happens.

const secondAddress = new AddressDto();
test.next(secondAddress);

// All current subscribers receive secondAddress.

// All future subscribers will receive secondAddress on subscribing.

Edit

You asked about storing the last value in a variable, which is ambiguous. I'm going to assume you mean at the source as that's more complex.

Once you get your head around the concept of Subject and Observable, you might understand the idea of the Observable Pipe. All sorts of stuff can happen inside a Pipe; think of it as a series of steps of things that can happen to an object. It is similar to a series of chained array functions on a normal array in JavaScript.

One of the things you can do in a Pipe is to perform "side effects" in a Tap operator. This means that you can do stuff in the middle of a Pipe while letting the data pass through it. To give two examples, you could store the value in a variable, or in localStorage.

If you have control of what's going in the Subject, it seems redundant to do this in a Pipe; therefore, the following example shows how to cache the result of an HTTP request.

this.http.get(url).pipe(
  // Transform the HTTP response into an object that is created.
  map(response => this.mapResponseToMyClass(response)),
  // Store the mapped object in a local property for later use.
  tap(myClass => {
    // Perform any 'side effect' actions you want, such as the below.
    console.log(myClass);
    // Store the value in a variable.
    this.cachedMyClass = myClass;
  })
);

'Piping' your own Subject is no different. Everything that goes into a Subject will go through a Pipe and is then outputted to the subscriber.

private subject = new Subject<AddressDto>();

getPostcode(): Observable<string> {
  // Reuse the local Subject. All subscribers to this function will receive addresses that have come through the Pipe.
  return subject.pipe(
    map(address => address.postcode),
    // Store the last postcode in a local property.
    tap(postcode => this.lastPostcode = postcode)
    // The postcode is outputted here to all subscribers
  ).asObservable();
}

Upvotes: 13

Ranjeet Jain
Ranjeet Jain

Reputation: 44

Observable does not store value. You should have subscribed to Observable before you have push data in Observable stream to receive value. I think Your AddressObservable is an Observable, not BehaviorSubject. If you convert AddressObservable to BehaviorSubject. It will work. In case AsyncPipe it is working because it async pipe subscribe for the same.

Change AddressObservable to type: BehaviorSubject

Upvotes: 1

Related Questions