Performance of an angular 2 application with Firebase - javascript

I have been creating a web application using angular2 with firebase (angularfire2),
I want to know if my development method is optimized or not.
When user select a group, I check if he is already member of the group.
ngOnInit() {
this.af.auth.subscribe(auth => {
if(auth) {
this.userConnected = auth;
}
});
this.router.params.subscribe(params=>{
this.idgroup=params['idgroup'];
});
this._groupService.getGroupById(this.idgroup).subscribe(
(group)=>{
this.group=group;
this.AlreadyPaticipe(this.group.id,this.userConnected.uid),
}
);
}
this method is work, but when I place the function AlreadyPaticipe(this.group.id,this.userConnected.uid) outside getGroupById(this.idgroup).subscribe() ,I get an error group is undefinded ,I now because angular is asynchrone. I don't khow how I can do it?. How I can optimize my code ?,How I can place the function AlreadyPaticipe(this.group.id,this.userConnected.uid) outside getGroupById(this.idgroup).subscribe()
Thanks in advance.

Everything as stream :
Well first, you shouldn't subscribe that much, the best practice is to combine your observables into one and subscribe to it just once, because everytime you subscribe, you need to cleanup when your component is destroyed (not for http, neither ActivatedRoute though) and you end up managing your subscription imperatively (which is not the aim of RXjs). You can find a good article on this topic here.
You must think everything as a stream, all your properties are observables :
this.user$ = this.af.auth.share(); //not sure of the share, I don't know firebase, don't know what it implies...
this.group$ = this.router.params.map(params => params["idgroup"])
.switchMap(groupID => this.groupService.getGroupById(groupID)).share();
// I imagine that AlreadyPaticipe return true or false, but maybe i'm wrong
this.isMemberOfGroup$ = Observable.combineLatest(
this.group$,
this.user$.filter(user => user !== null)
).flatMap(([group, user]) => this.AlreadyPaticipe(groupID, user.uid));
You don't even have to subscribe ! in your template you just need to use the async pipe. for example:
<span>user: {{user$|async}}</span>
<span>group : {{group$|async}}</span>
<span>member of group : {{isMemberOfGroup$|async}}</span>
Or if you don't want to use the pipe, you can combine all those observable and subscribe only once :
this.subscription = Observable.combineLatest(
this.group$,
this.user$,
this.isMemberOfGroup$
).do(([group, user, memberofGroup]) => {
this.group = group;
this.user = user;
this.isMemberofGroup = memberofGroup;
}).subscribe()
in this case, don't forget to this.subscription.unsubscribe() in ngOnDestroy()
there is a very handy tool on rxJS docs (at the bottom of the page) that helps you to choose the right operator for the right behavior.
I don't care about streams, I want it to work, quick n' dirty :
If You don't want to change your code too much, you could use a Resolve guard that will fetch the data before your component is loaded. Take a look at the docs:
In summary, you want to delay rendering the routed component until all necessary data have been fetched.
You need a resolver.

Related

How to pass a value from a service, to a component's method

I've got a service that I use to share data between 2 components. That part works flawlessly, but now I need to call a method of component A, when something triggers on the service (and pass a value to that component). How can I do this? I read on older questions that this is a wrong approach but since Im a noob I dont know what to search for a solution.
Do I need to use observables?
I think Joseph's idea is the way to go.
Here's how I'd implement it:
class FooService {
private _newEvents = new Subject();
newEvents$ = this._newEvents.asObservable();
addNewEvent (ev) {
this._newEvents.next(e);
}
}
// Allow `A` class to communicate with `B` class
class A {
addEvent (ev) {
this.fooService.addNewEvent(ev);
}
}
class B {
private subscription: Subscription;
ngOnInit () {
this.subscription = this.fooService.newEvents$
.subscribe(e => {})
}
ngOnDestroy () {
this.subscription.unsubscribe();
}
}
Note that if your B class subscribes to multiple observables, you should unsubscribe from them using, among other solutions, takeUntil.
Observables / Subjects are one way. You would have one Subject in the service, and would use .next(value) on it to exchange values. Each component which is interested in the value may subscribe to that subject.
Example: (taken from RxJS docs
//your Service
import { Subject } from 'rxjs';
const subject = new Subject<number>();
//Component A (and others as well)
service.subject.subscribe({
next: (num) => console.log(num)
});
//this should work as well with prettier syntax:
service.subject.subscribe(sum =>
console.log(num)
);
//Component B
service.subject.next(7) //passing number 7 to Component A
Whenever you create a subscription, make sure to always unsubscribe! Else you might end up with stacks of subscriptions, which will all get triggered simultaneously in the very same component.
From personal experience, I found it more helpful to outsource any functions and variables that could be considered as global into a dedicated service, if possible. If you directly read the variables of a service from your components (and modify them if necessary), you'll have the same effect. That works as long as you keep a proper service structure. Some examples of dedicated services with global use are:
Translations (TranslationService)
Rights Management (PermissionService)

One time operation on First subscription of observable

I am using Rxjs. I have one observable and multiple subscription from different sources. I wish to trigger one function only once after getting first subscription to the observable. Is there any way to achieve this?
Not sure if this fits your scenario, but I have dealt with this in the past as well and found it best to conditionally return a different observable after checking for an initialization variable of some kind. Below is a working example of what I mean.
Component wants a list of states from an API
this.statesService.getStates()
.subscribe((states) => this.states = states);
Service wants to only get the states once from the API
private _states: IState[];
getStates(): Observable<IState[]> {
if (!this._states) {
// we don't have states yet, so return an observable using http
// to get them from the API
// then store them locally using tap
return this.http.get<IState[]>('/options/states').pipe(
tap((answer) => {
this._states = answer;
}),
);
} else {
// subsequent calls will just return an observable of the data needed
return of(this._states);
}
}
In the case above, it's easy to return a conditional observable. Hopefully this provides you some ideas on how to handle your conditional (only on the first subscribe) scenario.
You can use publishReplay(1), refCount() operators. It will ensure to evaluate observable only once and share the same result to all subscribers.

React and Mobx - Load API data on load?

I have to validate that the user is logged in, using some token, that currently in the next example will already be set, for testing.
I have two options that I can think of.
Option 1
Do it on store's constructor:
export class MyStore {
#observable token = "sometoken";
#observable authenticated = false;
constructor() {
this.checkAuth();
}
#action
checkAuth() {
fetch("http://localhost:3001/validate/" + this.token)
.then(res => res.json())
.then(data => {
this.authenticated = data.validated;
});
// catch etc
}
}
Option 2:
Do it in my component's that uses the data, componentDidMount method.
Both of the ways work, but what is really the best practice to handle such state?
I would definitely go for the first option. If you don't always need the authentication - for example some parts are public - then just don't call this.checkAuth() in the store constructor. If all parts need authentication, then it looks good like this.
Option 2 should be avoided because that would make unnecessary roundtrips to the server to re-validate a token which was already validated. And in general MobX gives great tools to minimize the use of lifecycle methods and write a cleaner code.

Best way to chain observable subscriptions in Angular?

I have always nested subscriptions when I need to call a resource after getting the result of another one, like so:
this.paymentService.getPayment(this.currentUser.uid, this.code)
.valueChanges()
.subscribe(payment => {
this.payment = payment;
this.gymService.getGym(this.payment.gym)
.valueChanges()
.subscribe(gym => {
this.gym = gym;
});
});
I am using Angular v6 and AngularFire2.
Both endpoints (getPayment and getGym) return objects. Is there any more elegant way to do this without nesting one call inside another?
There are many resources available online to get an understanding of how this kind of scenarios can be addressed with rxjs.
Usually you end up using switchMap like this
this.paymentService.getPayment(this.currentUser.uid, this.code)
.pipe(
switchMap(payment => this.gymService.getGym(payment.gym))
)
.subscribe(
this.gym = gym;
)
I have skipped on purpose the valueChanges() call. I do not have any idea of what it does, but it does not sound as right in a reactive world.
This is a nice article about switchMap.

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