Reputation: 8935
I am using Ionic2
with Angularfire2
to access Firebase Authentication
.
I access 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 perfectly while a user is logged in (i.e. auth != null
), but a soon as a user logs out, and auth == null
, I get the following error:
ERROR Error: Uncaught (in promise): Error: permission_denied at /chat: Client doesn't have permission to access the desired data. Error: permission_denied at /chat: Client doesn't have permission to access the desired data.
Question
As you can see in the above code, I try to unsubscribe
from the Firebase Authentication Service, but must be doing it incorrectly. If anyone can advise how I should unsubscribe
in order to stop my app querying the Firebase database, I would appreciate the help.
Upvotes: 3
Views: 10222
Reputation: 9331
This is not an exact answer to the question, but my argument is we will never come to this issue if we do this other way.
P.S : I never used firebase , I use AWS so the firebase code might not be precise, we discuss about it .
Here is 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 raw but I hope it conveys the idea. Here I am observing on the user authentication status and doing flatMap
to fetch data. If user logs out, auth status change to null so in the UI data changes to empty list. Even if the user is not logged out , still he cannot see the data.
UPDATE :
Refactoring other 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 caching response using Subject
never use subscribe
inside service.
Upvotes: 1
Reputation: 8935
The unsubscribe
is working correctly. The problem turns out that the following function I used, is causing it to subscribe 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 (even though the function is only called once). This is creating a second subscription
, and the first subscription
is never unsubscribed
.
So it appears that the creation of the Observable
is incorrect. I'm not sure what;s the correct way to create the Observable
though.
Upvotes: 0