How to convert promise to observable angular2? - angular2-observables

I have used promise in angular2 but my requirement was done by the observable method.
Component.ts:-
constructor(private MenuService:MenuService, private router: Router ) {
this.getMenuPermissions().then(() => this.menuList = this.router.config);
}
ngOnInit() { }
getMenuPermissions(){
let promise = new Promise((resolve, reject) => {
this.MenuService.getMenuPermission()
.subscribe( res => {this.apiResponse = res},
err => reject(),
() => this.response(this.apiResponse, resolve)
);
});
return promise;
}
response(response, resolve)
{
if(response.api_status == 1)
{
this.menuPermissions = response.data;
return resolve();
}
}
My overall requirement is: - Call the service firstly and the call the HTML function. Using promise method is done but done by the observable method. I have no idea how to do? Please convert this code in the observable method.

You can done like this,
Observable.fromPromise(funcReturnsPromise())

Related

Ionic Storage : Strange behavior?

I try to use the Ionic Storage module to store some values, for example my authentication token :
/**
* Get Token
*/
public get token(): string {
this.storage.get(this.LS_TOKEN).then((val) => {
console.log(val);
this._token.next(val);
console.log( this._token.getValue());
});
return this._token.getValue();
// return 'testtttt';
}
I try multiple things, return directly the value, set the value and return the variable...
But I always got a null, and the thing that is strange is that if I return a string directly it works, when I console.log the val it show the string that I want, but the return is always null..
What am I doing wrong ?
Edit :
In response of the first answer I have tried this :
/**
* Get Token
*/
public get token() {
this.tokenPromise().then(yourToken => {
console.log(yourToken);
return yourToken;
});
}
public tokenPromise() {
return new Promise((resolve, reject) => {
this.storage.get(this.LS_TOKEN).then((val) => {
resolve(val);
}).catch(ex => {
reject(ex);
});
});
}
My problem is the same, in my components when I try to use : console.log(this.sharedService.token);
It's still null
It is not working with your new token() method.
It is still asnychron. Im gonna show you:
public get token() {
return new Promise((resolve, reject)=>{
this.storage.get(this.LS_TOKEN).then((val) => {
resolve(val);
}).catch(ex=>{
reject(ex);
});
});
}
Now you can use your token from the sharedservice like this:
this.sharedService.token.then(token=>{
//use token here;
});
or you can use await, but the function who is calling it, must be async:
async useTokenFromService(){
let token = await this.sharedService.token;
console.log(token);
}
You are getting a Promise from the storage.get() method.
This means it is running asynchron.
You can return Promise.
public get token() {
return new Promise((resolve, reject)=>{
this.storage.get(this.LS_TOKEN).then((val) => {
resolve(val);
}).catch(ex=>{
reject(ex);
});
});
}
And you can receive this with an async function and await the result:
async loadToken(){
let loadedToken = await this.token();
// use your loadedToken here...
}
Or you can use the .then method from the promise like this:
loadToken(){
this.token().then(yourToken=>{
// use the token yourToken here...
});
}

ionic 3 angularfire2 code to ionic 4 angularfire2 code

i have my code with ionic 3 angular 5 working as below
getUser(uid:string){
console.log('start of getUser with uid:' + uid)
return new Promise((resolve, reject) =>
{
this.db.object("/users/" + uid).snapshotChanges().map(
(snapshot) => {return snapshot.payload.val()}
).subscribe(
res => {
console.log('response:' + res)
resolve(res)
},
err => {
console.log(err)
reject(err)
}
)
})
}
however, with ionic 4 .map does not work any more. how do i convert this code?
Just like you can see here
Starting in version 5.5 we have shipped "pipeable operators", which
can be accessed in rxjs/operators (notice the pluralized "operators").
These are meant to be a better approach for pulling in just the
operators you need than the "patch" operators found in rxjs-compat
package.
NOTE: Using rxjs or rxjs/operators without making changes to your
build process can result in larger bundles.
So now you can use map() like this:
// RxJS
import { map } from 'rxjs/operators/map';
// ...
getUser(uid:string){
console.log('start of getUser with uid:' + uid)
return new Promise((resolve, reject) => {
this.db.object("/users/" + uid)
.snapshotChanges()
.pipe(
map((snapshot) => {
return snapshot.payload.val();
})
)
.subscribe(
res => {
console.log('response:' + res)
resolve(res)
},
err => {
console.log(err)
reject(err)
}
)
})
}
Not related to the question itself but just in case, if you want your getUser() method to return a promise, you can use RXJS operators as well (instead of creating and resolving a promise), like this:
// RxJS
import { map } from 'rxjs/operators/map';
import { tap } from 'rxjs/operators/tap';
// ...
public getUser(uid: string): Promise<any> {
console.log('start of getUser with uid:' + uid)
return this.db
.object("/users/" + uid)
.snapshotChanges()
.pipe(
map((snapshot) => {
return snapshot.payload.val();
}),
tap((response) => {
console.log('response:' + response);
})
)
.toPromise()
}

Return data in json after subscribe

I am using Angular 5 and want to return data from function getDionaeaResults in json format after subscribing to service
getDionaeaResults(sql) : any {
this.dionaeaService.getDionaeaConnectionLogs(sql).subscribe(res => {
this.data = res;
}),
(error: any) => {
console.log(error);
});
return this.data;
}
After calling this function, this.totalAttacks prints undefined.
getTotalAttack() {
this.totalAttacks = this.getDionaeaResults("some query")
console.log(this.totalAttacks,'attacks')
}
Would suggest using the Obseravable .map() function.
getDionaeaResults(sql) : Observable<any> {
return this.dionaeaService
.getDionaeaConnectionLogs(sql)
.map(res => res);
}
getTotalAttack(sql){
this.getDionaeaResults("some query")
.subscribe(
res => { this.totalAttacks = res; },
err => { console.log(err); }
);
}
this.getDionaeaResults is returning undefined because the service you're calling is asynchronous you have to wait for the subscribe callback. as Observables are asynchronous calls
this.data=res
might execute after the return statement. You can perhaps call that dionaeaService directly inside getTotalAttack() function, like this:
getTotalAttack(sql){
this.dionaeaService.getDionaeaConnectionLogs(sql).subscribe(res => {
this.totalAttacks = res;
}),
(error: any) => {
console.log(error);
});
}

Observable switch/flatMap fires instantly

I have the following code in my service:
public loginWithFacebook(): Observable<any> {
console.log('Login');
return Observable.fromPromise(this.fb.login()).flatMap((userData) => {
return this.http.post(authFacebook, {access_token: userData.authResponse.accessToken}, { observe: 'response' });
}).do( (response: HttpResponse<any>) => {
const token = response.headers.get('x-auth-token');
if (token) {
localStorage.setItem('id_token', token);
}
});
}
getFacebookProfile():Observable<any> {
console.log("Get Profile");
return Observable.fromPromise(this.fb.getLoginStatus())
.filter((state) => state.status === 'connected')
.switchMapTo(Observable.fromPromise(this.fb.api('/me')));
}
And later I use it in my component to get the profile info once login is successful.
this.profileData = this.usersService.loginWithFacebook()
.flatMapTo(this.usersService.getFacebookProfile());
However, for some reason getFacebookProfile() fires instantly even before the login procedure is complete. And I get an authentication error. Also, I have to login twice to get profile info displayed.
I've been always thinking that switchMap and flatMap only switch to the next observable once the previous one emits a value.
What am I doing wrong here?
--EDIT--
If I subscribe to the first Observable and call getFacebookProfile() in the subscription, everything works normally. But it's not very elegant solution I feel.
The problem is that promises are eager. You are calling this.fb.login() when you compose your observable and you are passing the returned promise into fromPromise.
That means that the login is initiated when loginWithFacebook is called and not when subscribe is called on the observable it returns.
If you want the login to be deferred until subscribe is called, you can use defer:
public loginWithFacebook(): Observable<any> {
console.log('Login');
return Observable.defer(() => Observable.fromPromise(this.fb.login()))
.flatMap((userData) => {
return this.http.post(authFacebook, {
access_token: userData.authResponse.accessToken
}, { observe: 'response' });
})
.do( (response: HttpResponse<any>) => {
const token = response.headers.get('x-auth-token');
if (token) {
localStorage.setItem('id_token', token);
}
});
}
For more information on using observables and promises, see Ben Lesh's article: RxJS Observable interop with Promises and Async-Await
It worked at last thanks to #cartant's answer. However, for some reason, I had to wrap it with defer operator twice. I would be thankful if someone could explain why it was necessary to do it. It's a bit weird.
public loginWithFacebook(): Observable<any> {
return Observable.defer(() =>
Observable.defer(() => this.fb.login()).flatMap((userData) =>
{
return this.http.post(authFacebook, {access_token: userData.authResponse.accessToken}, { observe: 'response' });
}).do( (response: HttpResponse<any>) => {
const token = response.headers.get('x-auth-token');
if (token) {
localStorage.setItem('id_token', token);
}
})
);
}
getFacebookProfile():Observable<any> {
return Observable.defer(() =>
Observable.defer(() => this.fb.getLoginStatus())
.filter((state) => state.status === 'connected')
.switchMapTo(Observable.fromPromise(this.fb.api('/me')))
);
}

GraphQL x MongoDB

I'm trying to read some data from a mongodb database with graphql and mongoose but everytime I query the db it returns null but no error is thrown.
Here's the code:
// Controller.js
exports.user_read = function(id) {
return new Promise((resolve, reject) => {
Contact.findById(id, function(err, user) {
err ? reject(err) : resolve(user);
}
});
}
// Resolver.js
var contact = require('Controller');
...
// root object passed as rootValue to graphqlHTTP
getUser: ({ id }) => {
contact.user_read(id)
}
...
Any tips and help would be appreciated.
P.S. This also seems to be happening with all my queries which take the same Promise format in the controller.js file.
You need to await contact.user_read(id). Without the await, you are simply sending back a Promise. It's most likely pending when it is returned, therefore the null return.
Including Daniel Rearden's suggestion to get rid of the extra Promise, here's what your code would look like:
// Controller.js
exports.user_read = async id => {
return Contact.findById(id, (err, user) => {
err ? reject(err) : resolve(user);
});
}
// Resolver.js
var contact = require('Controller');
...
// root object passed as rootValue to graphqlHTTP
getUser: ({ id }) => {
return await contact.user_read(id)
}
...