Angular 2 chain route params and http subscriptions - http

I am trying to get route params and then get data from the service
this.route.params
.switchMap(params => this.service.getData(params['id']))
.subscribe(value => this.value = value,
error => console.log(error));
This works fine, until first error. After the error this line doesn't calls no more params => this.noteService.GetParams(params['id']).
I can write something like this, but i think there is a better way
this.route.params.subscribe(
params => {
this.service.getData(params['id']).subscribe(
result => console.log(result),
error => console.log(error))
});
My service
public getData(id): Observable<any> {
return this.http.get('api/data/' + id)
.map(data => data.json())
.catch(error => Observable.throw(error));
}
Update
This answer helped me a lot to understand what is going on.
When I call Observable.throw(error) subscription to route params stops with an error. So instead of throwing error I just need to return empty observable.
my.component.ts
this.route.params
.switchMap(params => this.service.GetData(params['id']))
.subscribe(result => {
if (result) this.data = result;
else console.log('error');
});
my.service.ts
public GetData(id): Observable<any> {
let url = 'api/data' + id;
return this.http.get(url)
.map(data => data.json())
.catch(error => Observable.of(null));
}

I'm building a github users application right now and had the same problem.
Here is a solution that works for me:
users.service.ts
public getByUsername(username: string): Observable<any[]> {
return this.http
.get(`${this.url}/${username}`)
.map((res: Response) => res.json());
}
user.component.ts
ngOnInit() {
this.sub = this.route.params
.flatMap((v: any, index: number) => {
return this.usersService.getByUsername(v.name);
})
.subscribe(data => this.user = data);
}
So, basically the flatMap operator does the trick.
Here is link to another question,
helping me to figure out how things work with chaining RxJS Observables

Related

Firebase Cloud Functions / Each then() should return a value or throw promise/always-return

I was following the official firebase tutorial on promises (https://www.youtube.com/watch?v=7IkUgCLr5oA) but in my case, I cannot make it work.
const promise = userRef.push({text:text});
const promise2 = promise.then((snapshot) => {
res.status(200).json({message: 'ok!'});
});
promise2.catch(error => {
res.status(500).json({message: 'error'});
});
What am I doing wrong? Each then() should have its response in case something goes wrong, but that is why I am writing the promise2 catch.
Just add the return before sending the response.
const promise = userRef.push({text:text});
const promise2 = promise.then((snapshot) => {
return res.status(200).json({message: 'ok!'});
});
promise2.catch(error => {
return res.status(500).json({message: 'error'});
});
Also you can chain the promises as follows:
return userRef.push({text:text})
.then((snapshot) => {
return res.status(200).json({message: 'ok!'});
}).catch(error => {
return res.status(500).json({message: 'error'});
});

How to catch error with ngrx

I am trying to catch an error with ngrx and angularfire2 firetore.
Here is the effect
#Effect()
delete$: Observable<Action> = this.actions$
.ofType(actions.DELETE)
.map((action: actions.Delete) => action.id)
.mergeMap(id =>
of(this.afs.doc<Collection(`collections/${id}`).delete()))
.map(() => new actions.Success())
.catch(err => of (new actions.Fail(err.message )));
and actions:
export class Success implements Action {
readonly type = SUCCESS;
constructor() {
console.log('success')
}
}
export class Fail implements Action {
readonly type = ERROR;
constructor(public payload: any) {
console.log('failed');
}
}
I keep getting success even if the action is not completed. What is the good way to do this?
Currently, this code is trying to catch errors on the entire stream, rather than the inner observable that matters.
Try this:
#Effect delete$: Observable<Action> = this.action$
.ofType(actions.DELETE)
.map((action: actions.Delete) => action.id)
.mergeMap(id => {
return of(this.afs.doc<Collection(`collections/${id}`).delete())
.map(() => new actions.Success())
.catch(err => of(new actions.Fail(err.message))
});
See the docs on mergeMap and this helpful answer on SO about it. The stream that may throw an error is the internal of(this.afs.doc...) observable, so the .catch should be on that observable. In the current implementation (from your example above), it will always map the result of of(this.afs.doc...) to a new actions.Success(), whether it fails or not.

How use data from store in fetch action (react-redux)

How can I made fetch chain async actions where second fetch is using data from first? I need fetch repository list (GitHub API) and then fetch users from those repos. I made this:
export function reposListFetchData(url) {
return (dispatch) => {
dispatch(reposListIsLoading(true))
fetch(url)
.then((response) => {
if(!response.ok){
throw Error(response.statusText)
}
dispatch(reposListIsLoading(false))
return response
})
.then((response) => response.json())
.then((repos) => dispatch(reposListFetchSuccess(repos)))
.then( this.props.repos.map(
repo=>this.props.fetchContributorsData(`https://api.github.com/repos/angular/${repo.name}/contributors?per_page=100`)
))
.catch(()=> dispatch(reposListHasErrored(true)))
}
}
but of course I cant use this.props there. Any suggestions?
Assuming fetchContributorsData is an action that is quite similar with the reposListFetchData, you should be able to do this...
export function reposListFetchData(url) {
return dispatch => {
dispatch(reposListIsLoading(true));
fetch(url)
.then(response => {
if (!response.ok) {
throw Error(response.statusText);
}
dispatch(reposListIsLoading(false));
return response;
})
.then(response => response.json())
.then(repos => {
dispatch(reposListFetchSuccess(repos));
// where repos is an array of repo
repos.map(repo =>
dispatch(fetchContributorsData(`https://api.github.com/repos/angular/${repo.name}/contributors?per_page=100`))
);
})
.catch(() => dispatch(reposListHasErrored(true)));
};
}

Angular2 Observable HTTP Data not filled

I´m fairly new to Angular2 and want to load data from a JSON-file.
I read the AngularIO Article and did the tutorial, but i still need some help.
I splitted the "getting Data" into an apiService which loads data and a component, whicht gets the data from the apiService.
Because it´s simpler, for this question I want to load the data directly to the component without the apiService.
This is the component:
export class StatusComponent implements OnInit {
private status = {};
private error: string;
constructor(private router: Router, private variables: Variables, private apiService: ApiService, private http: Http) {
if (!this.variables.getIsLoggedIn()) {
this.router.navigate(['login']);
}
}
ngOnInit() {
this.getStatus();
}
getStatus() {
this.http.get('../app/apiFiles/status.json')
.map((res:Response) => res.json())
.subscribe(
data => { this.status = data},
err => console.error(err),
() => console.log('done')
);
console.log(JSON.stringify(this.status));
}
}
This is JSON:
{
"status": {
"timercount": "0",
"reccount": "0"
}
}
In the component, the getStatus() is correctly load, and goes through without an error, but the variable i fill status isn´t filled.
After the getStatus() the variable is still {}.
Moreover, the output of console.log(JSON.stringify(this.status)); is {}.
I hope someone can help me and solve it !
Thank so much!
That's because console.log(JSON.stringify(this.status)); is executed after http call is done. Have in mind that all http calls are asynchronous methods. Try this:
getStatus() {
this.http.get('../app/apiFiles/status.json')
.map((res:Response) => res.json())
.subscribe(
data => { this.status = data},
err => console.error(err),
() => console.log(this.status);
);
}
You'll see this will print your result because () => console.log(this.status); is executed after http call is successfuly completed.
The correct solution is this:
getStatus() {
this.http.get('../app/apiFiles/status.json')
.map((res:Response) => res.json())
.subscribe(
data => { this.status = data.status},
err => console.error(err),
() => console.log('done')
);
console.log(JSON.stringify(this.status));
}
So, you have to use data.status, because the JSON file begins with "status" ;)

Assign AJAX data to class variable in AngularJS2

I am doing the following code and unable to figure out that why the data I am obtaining through AJAX is not being assigned to the class variable which is this.users
Code Snippet
getUsers() {
this.http.get('/app/actions.php?method=users')
.map((res:Response) => res.json())
.subscribe(
res => { this.users = res}, // If I console 'res' here it prints as expected
err => console.error(err),
() => console.log('done')
);
console.log(this.users) // Printing 'undefined'
return this.users;
}
Any help will be much appreciated. This (http://prntscr.com/cal2l1) is link to my console output.
It is an asynchronous call, so you don't fetch data right away. However, if you setTimeout() on console.log(), it will be printed correctly because printing will occur after the data is fetched:
getUsers() {
this.http.get('/app/actions.php?method=users')
.map((res:Response) => res.json())
.subscribe(
res => { this.users = res}, // If I console 'res' here it prints as expected
err => console.error(err),
() => console.log('done')
);
setTimeout(() => {
console.log(this.users) // Printing 'undefined'
}, 1000);
return this.users;
}
Reason for Problem
Well, it was really a silly mistake which I was making here. Since, getUsers() was being called after the DOM was loaded so it was assigning the value to class variable which is this.users after loading of DOM which restricted my page to load the required values at page loading stage (not after page loading).
Solution
Angular2 comes with a hook called OnInit or ngOnInit(). I was supposed to call the function in this event as follows.
getUsers() {
this.http.get('/app/actions.php?method=users')
.map((res:Response) => res.json())
.subscribe(
res => { this.users = res},
err => console.error(err),
() => console.log('done')
);
console.log(this.users)
return this.users;
}
ngOnInit() {
getUsers();
}
Documentaion of OnInit: https://angular.io/docs/ts/latest/api/core/index/OnInit-class.html
Also the following documentation came up as a helping tool:
https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html

Resources