What's the pattern to manipulate data in Observables (angular2) - javascript

suppose we have this service
#Injectable()
export class CarService {
constructor (private http: Http) {}
getCars() {
return this.http.get('someurl')
.map(res => <Car[]> res.json())
.catch(this.handleError);
}
}
and we subscribe to this in another component. If Car looks like this:
class Car{
Color:string;
Timestamp:any; //this comes as a string in JSON but I want it to be of type Date object
}
and we want to have some logic, ie change date:string to date type, where should this be done?
in a service? and how?
in a class itself? will .map() hit the constructor of Car class?

I would put this process either:
in a map operator that leverages the map method of arrays
return this.http.get('someurl')
.map(res => <Car[]> res.json())
.map(data => {
data.map((d) => {
var date = (...)
return new Car(color, date);
});
return data;
})
.catch(this.handleError);
in the constructor of the Car class
return this.http.get('someurl')
.map(res => <Car[]> res.json())
.map(data => {
data.map((d) => {
return new Car(color, timestampAsString);
});
return data;
})
.catch(this.handleError);

Related

How to call a function that returns a promise from another module?

I'm trying to abstract away a data load function that uses promises, but now I'm unsure how to call that function from another module... :(
dataservice module
export default class DataService {
loadStudents() {
return window.fetch("data.json")
.then(res => res.json())
.then(res => {
// I want to return the result not a promise?
return res
})
}
}
main app module
import DataService from "../classes/dataservice"
const ds = new DataService()
ds.loadStudents().then(res => {
// here I just want the data, not a promise...
console.log(res)
})

Use Observable instead of Promise

I got this function in one of my servlets:
private setValues() {
this.config.socket.on('config.weather', (values:any) => {
console.log(values);
}
I want to outsource so I get something like this:
private setValues() {
this.config.load('weather').then((values:any) => {
console.log(values);
}
any in the socket Service:
public load(key: string) {
return new Promise(resolve => {
this.socket.on('config.' + key, values => resolve(values));
});
This works for the first call, but when the socket fires again it wont be send to the setValues() function because a Promise only works once.
I think I have to use an Observable, but I have no Idea where to place it.
I used a subject and now everything works fine:
public load(key: string) {
let sub = new Subject();
this.socket.on('config.' + key, values => {
sub.next(values);
});
return sub;
}
and
private setValues() {
this.config.load('weather').subscribe((values:any) => {
console.log(values);
}

typescript syntax angular2 promise then callback

i'm new to typescript and i can't find an alternative to optimize a line of code as you can see below. I need to filter an array derived from a callback function that i pass to a promise.then()...
getAllItems(): Promise<MyItem[]> {
return this.http.get(this.itemsUrl).toPromise()
.then(this.extractData)
.catch(this.handleError);
}
getItem(id: number | string): Promise<MyItem> {
var that = this; // i want to avoid to use this...
return this.http.get(this.itemsUrl).toPromise()
// ...just here
.then(function(res) {
return that.extractData(res).filter(h => h.id === +id)[0];
})
.catch(this.handleError);
}
private extractData(res: Response) {
let body = res.json();
return body.data || { };
}
Code above works well but i want to use a more short(more typescript i guess) syntax to achieve something like:
getItem(id: number | string): Promise<MyItem> {
return this.http.get(this.itemsUrl).toPromise()
// ... here again
.then(this.extractData => result.filter(h => h.id === +id)[0])
.catch(this.handleError);
}
obviously it does not work...any suggestion please? Thanks.
You still have to pass the response to your extractData method:
getItem(id: number | string): Promise<MyItem> {
return this.http.get(this.itemsUrl).toPromise()
// ... here again
.then(res => this.extractData(res).filter(h => h.id === +id)[0])
.catch(this.handleError);
}

Periodically updating Observable value in Angular2

I'd like to hit and display every 5 seconds from a http link, and it seems to be that using angular2, an observable would be the way to go?
getPhaseVotes(issue: string) {
return this.http.get(this.URL + 'issue/' + issue + '/getPhaseVotes')
.subscribe(data => this.phase_votes = data.json(),
err => console.log(err),
() => this.getStatus(issue));
}
How should I be updating this every 5 seconds?
You could use the interval operator of Observable:
#Injeactable()
export class SomeService {
constructor(private http:Http) {}
getPhaseVotes(issue: string) {
return Observable.interval(5000).flatMap(() => {
return this.http.get(this.URL + 'issue/' + issue + '/getPhaseVotes')
.map(res => res.json());
});
}
}
This way you need to call once the getPhaseVotes method and subscribe on it. Every 5 seconds, an HTTP request will be executed transparently and the result provided within the subscribed callback:
#Component({
(...)
})
export class SomeComponent {
constructor(private service:SomeService) {
this.service.getPhaseVotes('someissue')
.subscribe(data => this.phase_votes = data,
err => console.log(err),
() => this.getStatus(issue));
}
}
This article could give you more hints in its "Polling" section:
https://jaxenter.com/reactive-programming-http-and-angular-2-124560.html

Angular 2 Observables

I'm building an app to get some events from facebook, take a look:
EventComponent:
events: Object[] = [];
constructor(private eventService: EventService) {
this.eventService.getAll()
.subscribe(events => this.events = events)
}
EventService:
getAll() {
const accessToken = 'xxxxxxxxxxx';
const batch = [{...},{...},{...},...];
const body = `access_token=${accessToken}&batch=${JSON.stringify(batch)}`;
return this.http.post('https://graph.facebook.com', body)
.retry(3)
.map(response => response.json())
}
AuthenticationService:
getAccessToken() {
return new Promise((resolve: (response: any) => void, reject: (error: any) => void) => {
facebookConnectPlugin.getAccessToken(
token => resolve(token),
error => reject(error)
);
});
}
I have a few questions:
1) How can I set an interval to update the events every 60 seconds?
2) The value of accessToken will actually come from a promise, should I do something like this?
getAll() {
const batch = [{...},{...},{...},...];
this.authenticationService.getAccessToken().then(
accessToken => {
const body = `access_token=${accessToken}&batch=${JSON.stringify(batch)}`;
return this.http.post('https://graph.facebook.com', body)
.retry(3)
.map(response => response.json())
},
error => {}
);
}
3) If yes, how can I also handle errors from the getAccessToken() promise since I'm returning just the Observer?
4) The response from the post request will not return an array of objects by default, I'll have to make some manipulation. Should I do something like this?
return this.http.post('https://graph.facebook.com', body)
.retry(3)
.map(response => response.json())
.map(response => {
const events: Object[] = [];
// Manipulate response and push to events...
return events;
})
Here are the answers to your questions:
1) You can leverage the interval function of observables:
getAll() {
const accessToken = 'xxxxxxxxxxx';
const batch = [{...},{...},{...},...];
const body = `access_token=${accessToken}&batch=${JSON.stringify(batch)}`;
return Observable.interval(60000).flatMap(() => {
return this.http.post('https://graph.facebook.com', body)
.retry(3)
.map(response => response.json());
});
}
2) You could leverage at this level the fromPromise function of observables:
getAll() {
const batch = [{...},{...},{...},...];
return Observable.fromPromise(this.authenticationService.getAccessToken())
.flatMap(accessToken => {
const body = `access_token=${accessToken}&batch=${JSON.stringify(batch)}`;
return this.http.post('https://graph.facebook.com', body)
.retry(3)
.map(response => response.json())
});
}
3) You can leverage the catch operator to handle errors:
getAll() {
const batch = [{...},{...},{...},...];
return Observable.fromPromise(this.authenticationService.getAccessToken())
.catch(() => Observable.of({})) // <-----
.flatMap(accessToken => {
const body = `access_token=${accessToken}&batch=${JSON.stringify(batch)}`;
return this.http.post('https://graph.facebook.com', body)
.retry(3)
.map(response => response.json())
});
}
In this case, when an error occurs to get the access token, an empty object is provided to build the POST request.
4) Yes sure! The map operator allows you to return what you want...
Put the event inside a timeout block and set the interval of 60s. setTimeout(() => {},60000).
Using Template string is totally fine but you're telling its value comes from a promise. If your whole block of code is inside resolve function of promise this should fine. So it depends on where your code is. And why promises .In A2 it's recommended to use Observables and not promises. Don't mix them.
You're not returning anything in the error function. So if you return error from that block you'll get error data in case of error. error => erroror error => { return error; }.
Exactly you should you map to get the response and manipulate it and return just the array from that function. .map(resp => { return resp.array}). Since respons is in JSON format now you have to get array from it and return it. you can do as much modifications you want before returning it.
Feel free to edit the answer...

Categories