Do we need RXJS combineLatest with ActivateRouted.pathFromRoot? - javascript

The Angular Material Documentation application retrieves route parameters from lazy loaded route modules like this:
https://github.com/angular/material.angular.io/blob/master/src/app/pages/component-category-list/component-category-list.ts
// Combine params from all of the path into a single object.
this.params = combineLatest(
this._route.pathFromRoot.map(route => route.params), Object.assign);
It seems like we don't really need combineLatest for this?
The _route is constructor injected and IIUC once the component has the reference to it the pathFromRoot array of ActivateRoute instance cannot change?
Since that's the case we don't need combineLatest?
So it seems like we could do something like this instead:
const paramArr = this._route.pathFromRoot.map(route => route.params)
this.params = of(Object.assign(paramArr))
Does this make sense?

In
const paramArr = this._route.pathFromRoot.map(route => route.params)
pathFromRoute and therefore route won't change. But route.params is an Observable and this Observable can emit new values over time. To get notified when one of those Observables emits a new value you have to subscribe to all of those Observables. That's why combineLatest is used.
this.params = of(Object.assign(paramArr))
Isn't really helpful. It creates an Observable that emits an array of Observables so you'd have to flatten this Observable in another step. When you use combineLatest you won't need this extra step.

It seems like we don't really need combineLatest for this?
I'd say it is needed, but it also depends on what you'd want to achieve.
For instance, with this approach:
const paramArr = this._route.pathFromRoot.map(route => route.params)
this.params = of(Object.assign(paramArr))
You'd get the params from the ActivatedRoute root to the current ActivatedRoute child only once. Meaning that if the params of a route gets updated(e.g first you navigate to /1, then to /2), you'd only get 1.
Also, I'm not sure this would work as expected, since paramsArr will be an array of observables(ActivatedRoute.params is a BehaviorSubject AFAIK).
Whereas if you use this approach:
this.params = combineLatest(
this._route.pathFromRoot.map(route => route.params), Object.assign);
You will be notified of all the params updates that occur in the ActivatedRoute tree, not only once, but every time.
I've elaborated on how ActivatedRoute works(among other things) in this article.

Related

rxjs merge not working as expected in angular5

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/merge';
this.events = this.availableHoursCollection.valueChanges()
this.bla = this.afs.collection<AvailableHour>('users')
.doc('G2loKLqNQJUQIsDmzSNahlopOyk1').collection('availableHours');
this.test = this.bla.valueChanges();
this.something = Observable.merge(
this.events,
this.test
)
this.something only has the items of the last observable, how can I combine them?
Also if you have observables with the same value id, how can you merge the values?
Using an AngularFire test bed, I ran you Rx scenario
const merged = Observable.merge(o1, o2)
and I got an observable which emits twice, each emit containing an array which is the result of each query.
This leads me to wonder how you're checking the output. If piping to a template with the async pipe {{ results | async }}, then the second emit will over-write the first and give the impression that only the second emits.
Apologies if you're well aware of that.
If you need a single emit of the two arrays combined, there are a number of ways to do so. The best for this scenario is combineLatest().
const combined = Observable.combineLatest(o1, o2)
.map(([s1, s2]) => [...s1, ...s2])
The reason this is best is because .valueChanges() is designed to keep pushing changes, so it never completes. So methods based on forkJoin() or
Observable.merge(o1.mergeMap(x => x), o2.mergeMap(x => x)).toArray()
both require a completed event to emit anything, whereas combineLatest() does not and the combined observable will emit again whenever one of the sources is updated.

How to push to Observable of Array in Angular 4? RxJS

I have a property on my service class as so:
articles: Observable<Article[]>;
It is populated by a getArticles() function using the standard http.get().map() solution.
How can I manually push a new article in to this array; One that is not yet persisted and so not part of the http get?
My scenario is, you create a new Article, and before it is saved I would like the Article[] array to have this new one pushed to it so it shows up in my list of articles.
Further more, This service is shared between 2 components, If component A consumes the service using ng OnInit() and binds the result to a repeating section *ngFor, will updating the service array from component B simultaneously update the results in components A's ngFor section? Or must I update the view manually?
Many Thanks,
Simon
As you said in comments, I'd use a Subject.
The advantage of keeping articles observable rather than storing as an array is that http takes time, so you can subscribe and wait for results. Plus both components get any updates.
// Mock http
const http = {
get: (url) => Rx.Observable.of(['article1', 'article2'])
}
const articles = new Rx.Subject();
const fetch = () => {
return http.get('myUrl').map(x => x).do(data => articles.next(data))
}
const add = (article) => {
articles.take(1).subscribe(current => {
current.push(article);
articles.next(current);
})
}
// Subscribe to
articles.subscribe(console.log)
// Action
fetch().subscribe(
add('article3')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.2/Rx.js"></script>
Instead of storing the whole observable, you probably want to just store the article array, like
articles: Article[]
fetch() {
this.get(url).map(...).subscribe(articles => this.articles)
}
Then you can manipulate the articles list using standard array manipulation methods.
If you store the observable, it will re-run the http call every time you subscribe to it (or render it using | async) which is definitely not what you want.
But for the sake of completeness: if you do have an Observable of an array you want to add items to, you could use the map operator on it to add a specified item to it, e.g.
observable.map(previousArray => previousArray.concat(itemtToBeAdded))
ex from angular 4 book ng-book
Subject<Array<String>> example = new Subject<Array<String>>();
push(newvalue:String):void
{
example.next((currentarray:String[]) : String[] => {
return currentarray.concat(newValue);
})
}
what the following says in example.next is take the current array value Stored in the observable and concat a new value onto it and emit the new array value to subscribers. It is a lambda expression.I think this only works with subject observables because they hold unto the last value stored in their method subject.getValue();

What is the difference between Observable and a Subject in rxjs?

I was going through this blog and reading about Observables and couldn't figure out the difference between the Observable and a Subject.
In stream programming there are two main interfaces: Observable and Observer.
Observable is for the consumer, it can be transformed and subscribed:
observable.map(x => ...).filter(x => ...).subscribe(x => ...)
Observer is the interface which is used to feed an observable source:
observer.next(newItem)
We can create new Observable with an Observer:
var observable = Observable.create(observer => {
observer.next('first');
observer.next('second');
...
});
observable.map(x => ...).filter(x => ...).subscribe(x => ...)
Or, we can use a Subject which implements both the Observable and the Observer interfaces:
var source = new Subject();
source.map(x => ...).filter(x => ...).subscribe(x => ...)
source.next('first')
source.next('second')
Observables are unicast by design and Subjects are multicast by design.
If you look at the below example, each subscription receives the different values as observables developed as unicast by design.
import {Observable} from 'rxjs';
let obs = Observable.create(observer=>{
observer.next(Math.random());
})
obs.subscribe(res=>{
console.log('subscription a :', res); //subscription a :0.2859800202682865
});
obs.subscribe(res=>{
console.log('subscription b :', res); //subscription b :0.694302021731573
});
This could be weird if you are expecting the same values on both the subscription.
We can overcome this issue using Subjects. Subjects is similar to event-emitter and it does not invoke for each subscription. Consider the below example.
import {Subject} from 'rxjs';
let obs = new Subject();
obs.subscribe(res=>{
console.log('subscription a :', res); // subscription a : 0.91767565496093
});
obs.subscribe(res=>{
console.log('subscription b :', res);// subscription b : 0.91767565496093
});
obs.next(Math.random());
Both of the subscriptions got the same output value!
Observables
They are cold: Code gets executed when they have at least a single observer.
Creates copy of data: Observable creates copy of data for each observer.
Uni-directional: Observer can not assign value to observable(origin/master).
The code will run for each observer . If its a HTTP call, it gets called for each observer.
if its a service we want to share among all the components, it wont have latest result all new subscribers will still subscribe to same observable and get value from scratch
Unicast means can emit values from the observable not from any other component.
Subject
They are hot: code gets executed and value gets broadcast even if there is no observer.
Shares data: Same data get shared between all observers.
bi-directional: Observer can assign value to observable(origin/master).
If are using using subject then you miss all the values that are broadcast before creation of observer. So here comes Replay Subject
multicast, can cast values to multiple subscribers and can act as both subscribers and emmitter
I found the accepted answer slightly confusing!
An Observer isn't the interface for feeding an Observable source, it's the interface for observing an Observable source... which makes more sense from the name, right?
So, the reason that:
var observable = Observable.create(observer => {
observer.next('first');
observer.next('second');
...
});
works - creating an observable which emits 'first' then 'second' - is that the argument to Observable.create(...) is a subscribe function, it basically defines which Observer events will happen on a direct Observer of that Observable.
If you want to go into it a little bit further again, it's important to understand that the subscribe function isn't directly called on the Observer object when you subscribe, instead it's mediated by a Subscription object which can enforce correct observable rules, e.g. that an Observable will never emit a new value after observer.complete() has been called, even if your subscribe function looks as if it would.
REF: http://reactivex.io/rxjs/manual/overview.html#creating-observables
A Subject is both an Observable and an Observer and once again it looks just like the Observer interface is the way to 'feed' events to the Subject. But it's easier to understand the naming if you realise that a Subject is a bit like an Observable with the equivalent of the subscribe function (i.e. where you define what events will happen to things observing it) sitting there right on the object, even after it has been created. So, you call Observer methods on the Subject to define what Observer events will happen on things observing it! 😊 (And again, there are intermediate objects involved, to make sure that you can only do legal sequences of things.)
REF: http://reactivex.io/rxjs/manual/overview.html#subject
See rxjs document (more information and examples there):
http://reactivex.io/rxjs/manual/overview.html#subject
What is a Subject? An RxJS Subject is a special type of Observable that allows values to be multicasted to many Observers. While plain Observables are unicast (each subscribed Observer owns an independent execution of the Observable), Subjects are multicast.
A Subject is like an Observable, but can multicast to many Observers. Subjects are like EventEmitters: they maintain a registry of many listeners.
and code, Subject extending Observable: https://github.com/ReactiveX/rxjs/blob/master/src/internal/Subject.ts#L22
/**
* #class Subject<T>
*/
export class Subject<T> extends Observable<T> implements SubscriptionLike {
//...
}
Imagine if you have a stream of data coming into your application like in a websocket connection. You want a way to handle it. There is a few solution:
1. normal ajax request:
This solution is not viable because it is
not applicable to process push data. It is more of a pull then a
push.
2. Promise:
Also not good because you have to trigger them and
they can only retrieve once. Also more of a pull then a push.
So in order to retrieve this data, in the old time, we do a long-polling. Which is where we set an interval function to retrieve that stream of data every 1 minute for an example. Though it works, it actually burdening resources like CPU and memory.
But now with option no 3,
3. Observable: You can subscribe and let the stream of data to come
in non-stop until the function complete has been called.
Cool right ? But then there is another problem. What if you want to observe incoming data only once somewhere in your application. But you want to use that data simultaneously around your application when the data arrived. That is when and where you use Subject.
You place subject.subscribe() at places you want to use throughout your application. When the data arrived, places where there is subject.subscribe() will process them simultaneously. But the observer must subscribe with the subject as its argument like this.
observer.subscribe(subject).
Example application is when you want to build a notification alert.
You cannot have multiple subscription of the same observable because chances are, each subscribers will received different input data. But with subject, all that subscribe() through subject will be retrieving the same data.
Another analogy is through magazine subscription. Each subscribers will received the magazine with their name on it. So, different subscription = different receiver name.(Normal Observable)
But when you share with your friends, all of your friend would receive the same magazine with only your name on it.(Normal Observable with Subject)
This guy explain it very well with code example. You can check it out at https://javascript.tutorialhorizon.com/2017/03/23/rxjs-subject-vs-observable/
Hopefully this answer helps.
Briefly,
subject: you can send to it and receive from it.
Observable: you can receive from it only.
In another words,
In subject you can subscribe to it and you can use it to broadcast to other subscribers any time and anywhere in code.
whilst,
in observable you can subscribe to it only (you can't use it to broadcast data after it have been initialized).
The only place you can broadcast data from observable is inside its constructor.
Observable can inform only one observer, while Subject can inform multiple observers.
From another perspective, it is good to note that the subscription to an Observable re-execute the Observable function. This can lead performance issue if the data source is a service for instance.
If you want several subscribers to get the same value, you may need a Subject.
For this, make sure that your subscription is set before the Subject subscribed to the data source. Otherwise, your process would be stuck.
More details here: https://javascript.tutorialhorizon.com/2017/03/23/rxjs-subject-vs-observable/
Observable:
Only the Observable knows how and when the events are triggered on the observable. i.e the next() method has to be called only inside the instantiated constructor. Also, on subscribing each time, a separate observer is created and calls next() method using particular observer inside constructor only, in the following example subscriber itself is the observer and it is subscribed when the instantiated constructor gets executed.
Ex:
import { Observable } from 'rxjs';
const observable = new Observable(subscriber => {
subscriber.next(1);
subscriber.next(2);
setTimeout(() => {
subscriber.next(3);
}, 1000);
});
Subject:
Here next() method can be used by subject anywhere outside the constructor. Also, when next() method is called before subscribing, the particular event will be missed. Hence next() method has to be called only after subscribing.
Ex:
import { Subject } from 'rxjs';
const subject = new Subject<number>();
subject.next(1); // this is missed
subject.subscribe({
next: (v) => console.log(`observerA: ${v}`)
});
subject.subscribe({
next: (v) => console.log(`observerB: ${v}`)
});
subject.next(2);

Observable instance emit without an observer (or subscriber ?)

I am using observable in Angular2. As I know so far, each Observable instance come with an observer(1:1), and when we emit something with observer.next(value) we can get that value with observable.subscribe((value) => {}).
var observable = Observable.create(observer => {
observer.next(value);
}
.map(value=>{})
.catch(...)
observable.subscribe(value => {
console.log(value);
})
How can I emit value without knowing the corresponding observer, because I want to emit value outside create function. One possible solution is save observer into some global variable but I think an observable should be enough. Any suggestion for this ??
You're mixing multiple things together. Observables are not in 1:1 relation with Observers (more precisely it's 1:N). If you want to be able to manually emit values you need a Subject which acts as an Observable and an Observer at the same time. Practically this means you can call its next() method and it'll propage the value to all its subscribers (Observers).
For example consider the following code in TypeScript:
import {Subject} from 'rxjs';
let source = new Subject();
source.subscribe(val => console.log('Observer 1:', val));
source.subscribe(val => console.log('Observer 2:', val));
source.next(42);
source.next('test');
This will print to console:
Observer 1: 42
Observer 2: 42
Observer 1: test
Observer 2: test
See live demo: http://plnkr.co/edit/gWMFMnPlLJVDC1pQi8pH?p=preview
Read more:
http://reactivex.io/intro.html
https://github.com/Reactive-Extensions/RxJS#resources
https://github.com/Reactive-Extensions/RxJS/blob/master/doc/gettingstarted/creating.md
Be aware that Observable.create() is a very different animal. It takes as a parameter a function that is called every time a new Observer subscribes. That's why it take the newly subscribed Observer as an argument. In this function you can for example call next() method on the Observer to send it some default value that all subscribes need to receive.
So you probably want to use Subject instead of Observable.create().

What are RxJS Subject's and the benefits of using them?

I found the rxJS docs define them as
What is a Subject? An RxJS Subject is a special type of Observable that allows values to be multicasted to many Observers. While plain Observables are unicast (each subscribed Observer owns an independent execution of the Observable), Subjects are multicast.
and it goes on to give examples but I'm looking for a basic ELI5 explanation. From my understanding is it helps handle and define items in a sequence. Is that correct?
I think it would be most helpful to me and others to see a simple function with and without defining an rxJS Subject to understand why it's important?
Thanks!
The easiest way to understand it is to think of a Subject as both a producer and a consumer. It's like an open channel where someone can send a message on one end, and any subscribers will receive it on the other end.
+---------------
Sender | => => => => Subscriber
-----------------------+ +-----------
Message => => => => => => => => => => => Subscriber
-----------------------+ +-----------
| => => => => Subscriber
+---------------
In code terms say you have a service with a subject
class MessageService {
private _messages = new Subject<Message>();
get messages: Observable<Message> {
return this._messages.asObservable();
}
sendMessage(message: Message) {
this._messages.next(message);
}
}
Note the messages getter returning the Subject as an Observable. This is not required. The Subject is already an observable, and anybody could subscribe directly to the Subject. But I think the asObservable pattern is used as a way to limit what users can do with it, i.e. so users only use it to subscribe to, and not emit to. We save the emitting for the sendMessage method.
Now with this service in place, we can inject it into different components, and this can be a way for two (or more) arbitrary components to communicate (or just receive arbitrary event notifications).
class ComponentOne {
constructor(private messages: MessageService) {}
onClick() {
this.messages.sendMessage(new Message(..));
}
}
class ComponentTwo {
constructor(private messages: MessageService) {}
ngOnInit() {
this.messages.messages.subscribe((message: Message) => {
this.message = message;
});
}
}
Angular's own EventEmitter is actually a Subject. When we subscribe to the EventEmitter, we are subscribing to a Subject, and when we emit on the EventEmitter, we are sending a message through the Subject for all subscribers.
See also:
Subject vs BehaviorSubject vs ReplaySubject in Angular
Subjects are useful when the code you're in is the one that is actually originating the observable data. You can easily let your consumers subscribe to the Subject and then call the next() function to push data into the pipeline.
If, however, you are getting data from other source and are just passing it along (perhaps transforming it first), then you most likely want to use one of the creation operators shown here, such as Rx.Observable.fromEvent like so:
var clicks = Rx.Observable.fromEvent(document, 'click');
clicks.subscribe(x => console.log(x));
This allow you to stay in the functional paradigm, whereas using a Subject, while it has its uses, is considered by some to be a smell that you're trying to force imperative code into a declarative framework.
Here is a great answer that explains the difference in the two paradigms.
If you want the most simple explanation ...
Observables are usually the result of something. The result of an http call, and whatever you do with a pipe returns an observable.
But what is the source of those things? Ever wondered how you hook your user events into the whole rxjs thing? The main feature of subjects is that you can call the next() method on them.
When doing reactive programming, the first step is usually to make a list of possible subject you will have.
For instance: lets say we have to make a todo-list app.
We will probably have a couple of variables in our component:
public deleteItem$ = Subject<TodoItem> = new Subject();
public addItem$ = Subject<TodoItem> = new Subject();
public saveList$ = Subject<TodoItem[]> = new Subject();
and in our applicatiuon we will hook these up like this:
<button (click)="deleteItem$.next(item)">Delete</button>
Using rxjs, we will use operators like merge/combineLatest/withLatestFrom to handle these subjects and define our application logic.
I'll see if I can find the time to make a small example.
You can find a study of the semantics of subjects here.
All answered I see are correct. I'll just add that the term subject comes from the observer pattern (cf. https://en.wikipedia.org/wiki/Observer_pattern). As such a subject is sort of a relay, it receives something on one end, and emit it on any of its ends (subscriptions).

Categories

Resources