Quick Summary: Can someone help me figure out how to get an Observed array to complete? Check out this jsBin example for reference.
I'm a beginner with Observables so I might be approaching this problem the wrong way. With the code provided below, or in this jsBin link, what changes should I make to ensure the User's sites array completes?
let firstUser = {
name: 'Susan',
sites: [
{company: 'ABC Co', role: 'admin'},
{company: 'XYZ Co', role: 'reader'}
]
};
user = new Rx.BehaviorSubject(firstUser);
function authorized(authRoles) {
// check if the current user has one of the authorizedRoles roles
return this.user
.do(user => console.log("Checking user: ",JSON.stringify(user)))
.flatMap( user => user.sites )
.do(res => console.log("Mapped user roles: ",res))
.first( site => authRoles.indexOf(site.role) !== -1 ) // only return when a role matches
.do( res => console.log('First: ',res))
.map( res => true)
}
// This one finds a match and completes
authorized(['writer','admin','reader']).subscribe(res =>{
console.log("1: isAuthorized?: ",res);
}, err => {
console.log("1: ERROR: User is not authorized!");
}, () => {
console.log("1: Authorized check completed!");
});
// This one never completes
authorized(['writer','foo']).subscribe(res =>{
console.log("2: isAuthorized?: ",res);
}, err => {
console.log("2: ERROR: User is not authorized!");
}, () => {
console.log("2: Authorized check completed!");
});
Please note that if (first)[http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-first] doesn't find a match it will throw an error, but only if the Observable completes.
The code above works correctly and completes if there's a match, however, it will neither complete nor throw an error without a match because the array of user.sites never completes.
Is there a way to force the array to complete? I managed to make it work by fetching/subscribing to the user first:
//
// Pretend that fetchedUser is fetched in a safer/more sane way
// fetch the user and set it
let fetchedUser;
user.subscribe(user => fetchedUser = user);
function authorized2(authRoles) {
// check if the current user has one of the authorizedRoles roles
return Rx.Observable.of(this.fetchedUser.sites)
.do(sites => console.log("auth2: Checking users sites: ",sites))
.flatMap( sites => sites )
.do(res => console.log("Mapped user roles: ",res))
.first( site => authRoles.indexOf(site.role) !== -1 ) // only return when a role matches
.do( res => console.log('First: ',res))
.map( res => true)
}
I feel like there's a simple step I'm missing to make this work with pure Observables. Thank you in advance for your assistance!