RxJs get value from observable
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}}
How to get value from Observable
You need to subscribe to the items$
Observable to get the data.
jobsLength() {
this.searchLogic.items$.subscribe((value: any[]) => {
let jobs: any[] = value;
console.log(jobs);
console.log(jobs.length);
});
}
Sample Solution on StackBlitz
References
Observable (Subscribing)
Get value of Observable<SomeObject> in an object
Angular 8 How to get value from observable in ngOnInit and how do they behave
The getLights
function returns an Observable
. The Observable
itself doesn't block the execution, it only holds the information if a result is available. To get notified when a result is available a subscription with a callback function will be registered on the observable by the subscribe
function. Within the callback the resulting data will be present.
As mentioned above the observable does not block the execution of your code, nor does the subscribe call. That means:
- A callback will be registered which will print
Test: 1.1
but isn't fired yet, because the http request didn't complete yet. So nothing is printed. - The code execution continues and prints
Test: 1.2
withundefined
as result, because the previous subscription didn't fire and so didn't set a value forthis.test1
. - Some time later the callback of the subscription is executed because a result arrived and so
Test: 1.1
will be printed with the result.
If you want to explicitly block execution after registering a subscription to retrieve the result first, you can do the following:
async ngOnInit(): void {
console.log("----- ngOnInit -----");
this.test1 = await this.ExperimentalService.getLights().toPromise();
console.log("Test: 1.2", this.test1); // --- 1.2 ---
}
Note: It's important that the
ngOnInt
itself is awaitable.
This will implicitly register a subscription which will be converted into a Promise. The Promise will hold the last value emitted, after the Observable has completed. Because Angular's Http-Client completes the returned Observable after it received a value, the resulting Promise will be resolved when the request was successful or rejected on an error.
You can turn any Observable into a Promise, but you must ensure that the Observable is completed at some point in the future or it will wait (block) forever. To ensure this, mostly a pipe is registered with the first()
operator:
async ngOnInit(): void {
console.log("----- ngOnInit -----");
this.test1 = this.ExperimentalService.getLights().pipe(first()).toPromise();
console.log("Test: 1.2", this.test1); // --- 1.2 ---
}
Note:
first()
[doc] will complete the Observeable when the first value is emitted and passes it through to the subscription.
For a http requestfirst()
is redundant, because the Observable will be completed at the latest when the http request runs into a timeout.
Get value from Observable on object property
You can use ResultSelector function from a flattening operator (like switchMap
, flatMap
etc.):
obs = of({ prop1: 'foo', prop2: of('bar') }).pipe(
switchMap(val => val.prop2,
(a, b) => ({a, b})
).subscribe(console.log)
How can I get value of RxJs Observable in a nested array of objects to resolve?
You need to use a "Higher order mapping operator" (switchMap
) which will subscribe to your inner observable source and emit the data you need. In your case, you need to make many calls (one for each file), so you can map your file list to an array of observables that emit the desired data. You can use forkJoin
again to wrap all these calls into a single observable:
function getData() {
return forkJoin([filesApiRequest, userApiRquest]).pipe(
switchMap(([files, userInfo]) => forkJoin(
// return array of observables
files.getFilesList().map(f => toDataWithImportantInfo$(f, userInfo))
))
);
}
function toDataWithImportantInfo$(file, userInfo) {
const name = file.getname();
return importantInfoCall(userInfo.name, name).pipe(
map(importantInfo => ({
data1,
data2,
name,
...,
hasImportantInfo: importantInfo
})
);
}
forkJoin
isn't the best solution when you have a large number of requests, because it will execute them all at the same time (maybe you don't want to kick off 500 http requests at once).
In order to limit the number of requests, we can use merge
instead, since it provides a concurrency parameter:
function getData() {
return forkJoin([filesApiRequest, userApiRquest]).pipe(
switchMap(([files, userInfo]) => merge(
files.getFilesList().map(f => toDataWithImportantInfo$(f, userInfo))
, 5)), // MAX 5 CONCURRENT
toArray()
);
}
forkJoin
emits an array of all results when all sources complete. merge
emits each result individually, so toArray
is needed if you want to emit a single array once all the inner sources complete (rather than emitting individually).
Related Topics
Fetch - Missing Boundary in Multipart/Form-Data Post
Image Resizing Client-Side With JavaScript Before Upload to the Server
Refresh Page and Keep Scroll Position
How to Protect HTML Form from Blank Submission
How to Convert All Elements in an Array to Integer in JavaScript
Converting Byte Array to String in JavaScript
Observe Localstorage Changes in Js
How to Sort a Map by Value in JavaScript
How to Concatenate a Variable for a Hyperlink
Javascript Return True or Return False When and How to Use It
How to Check If a Cookie Exists
Find Minimum Numbers of Currency for Required Amount
How to Render a Collection of Children Using Array
Convert 12-Hour Hh:Mm Am/Pm to 24-Hour Hh:Mm
React Button Onclick Redirect Page
Allowing/Replacing Comma as Number Separator for Input Type="Number" Using Rails
How to Apply CSS to Parent Using Child Selector - With CSS or Angular 2