Firebase how to unsubscribe
I am using Ionic2
c Angularfire2
to access Firebase Authentication
.
I am accessing the following rxjs/Observable
:
chats.ts
this.firelist = this.dataService.findChats();
this.subscription = this.firelist.subscribe(chatItems => {
...
});
ngDestroy() {
this.subscription.unsubscribe();
}
dataService.ts
findChats(): Observable<any[]> {
this.firebaseDataService.findChats().forEach(firebaseItems => {
...
observer.next(mergedItems);
});
}
firebaseDataService.ts
findChats(): Observable<any[]> { // populates the firelist
return this.af.database.list('/chat/', {
query: {
orderByChild: 'negativtimestamp'
}
}).map(items => {
const filtered = items.filter(
item => (item.memberId1 === this.me.uid || item.memberId2 === this.me.uid)
);
return filtered;
});
}
Also, in Firebase Authentication I have the following realtime database rules:
"rules": {
".read": "auth != null",
".write": "auth != null",
}
Problem
This works fine when the user is logged in (i.e. auth != null
), but as soon as the user is logged out as well auth == null
, I get the following error:
ERROR error: impurity (in the promise): error: allowed in / chat: The client does not have access to the requested data. Error: permission_denied at / chat: The client does not have permission to access the required data.
Question
As you can see in the above code, I am trying to execute unsubscribe
from the Firebase Authentication Service, but you must be doing it wrong. If anyone can advise on how I should be able unsubscribe
to stop the application querying the Firebase database, I would appreciate some help.
source to share
This is not an accurate answer to the question, but my argument is that we will never get to this problem if we do it differently.
PS: I have never used firebase, I am using AWS, so the firebase code may not be accurate, we are discussing it.
Here's my version:
findChats(): Observable<any[]> { // populates the firelist
return
this.authService.getCurrentUser()
.flatMap(user => user === null ?
Observable.empty():
this.af.database.list('/chat/', {
query: {
orderByChild: 'negativtimestamp'
}
})
.map(items =>
return items.filter(
item => (
item.memberId1 === this.me.uid ||
item.memberId2 === this.me.uid
)
)
)
);
}
Auth Service
public currentUser = new BehaviorSubject(null);
constructor(){
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
currentUser.next(user);
} else {
// No user is signed in.
currentUser.next(null);
}
});
}
The code is very crude, but I hope it conveys the idea. Here I am observing user authentication status and doing flatMap
to fetch data. If the user logs out, the authentication state goes to zero, so the result of changing the UI data to an empty list. Even if the user is not logged out, they still cannot see the data.
UPDATE :
Refactoring another answer:
findChats(){
return Observable.merge(
this.firebaseDataService
.findChats()
.flatMap(chats => Observable.from(chats)),
this.localDataService
.findChats()
.flatMap(chats => Observable.from(chats))
)
.filter(chat => !!chat)
.toArray()
.map(chats => [
...chats.sort(
(a, b) =>
parseFloat(a.negativtimestamp) - parseFloat(b.negativtimestamp))
]
);
}
Except when you are doing caching with Subject
never use subscribe
inside a service.
source to share
unsubscribe
works correctly. The problem is that the following function that I have used causes it to be signed twice for some reason:
findChats(): Observable<any[]> {
return Observable.create((observer) => {
this.chatSubscription2 = this.firebaseDataService.findChats().subscribe(firebaseItems => {
this.localDataService.findChats().then((localItems: any[]) => {
let mergedItems: any[] = [];
if (localItems && localItems != null && firebaseItems && firebaseItems != null) {
for (let i: number = 0; i < localItems.length; i++) {
if (localItems[i] === null) {
localItems.splice(i, 1);
}
}
mergedItems = this.arrayUnique(firebaseItems.concat(localItems), true);
} else if (firebaseItems && firebaseItems != null) {
mergedItems = firebaseItems;
} else if (localItems && localItems != null) {
mergedItems = localItems;
}
mergedItems.sort((a, b) => {
return parseFloat(a.negativtimestamp) - parseFloat(b.negativtimestamp);
});
observer.next(mergedItems);
this.checkChats(firebaseItems, localItems);
});
});
});
}
For some reason, the 3rd line above is called twice (although the function is only called once). This creates the second subscription
and the first subscription
never unsubscribed
.
So it looks like the creation Observable
is wrong. I'm not sure if this is the correct way to create Observable
.
source to share