Asynchronous call of two functions in Angular 2 using promise - javascript

I have the following method in auth.nav.service.ts:
public login () {
this.authService.login();
this.navService.redirectAfterLogin();
}
in nav.service.ts:
public redirectAfterLogin () {
let nav = this.app.getRootNav();
nav.setRoot(TabsPage);
nav.popToRoot();
}
In Auth.service.ts:
public login() {
const client = new Auth0Cordova(auth0Config);
const options = {
scope: 'openid profile offline_access'
};
client.authorize(options, (err, authResult) => {
if(err) {
throw err;
}
this.setIdToken(authResult.idToken);
this.setAccessToken(authResult.accessToken);
const expiresAt = JSON.stringify((authResult.expiresIn * 1000) + new Date().getTime());
this.setStorageVariable('expires_at', expiresAt);
this.auth0.client.userInfo(this.accessToken, (err, profile) => {
if(err) {
throw err;
}
profile.user_metadata = profile.user_metadata || {};
this.setStorageVariable('profile', profile);
this.zone.run(() => {
this.user = profile;
});
});
});
}
I want to have the login function ran successfully and the use the RedirectAfterLogin. How can I do that with Promise ? I'm using Angular 2, Ionic-Native 3 and auth0.

I made it work with a promise, and fixing the scope of the variables (this) inside the then scope.
auth.view.service.ts
public login () {
var t = this; // this scope is lost inside the then.
this.authService.login().then(function (response){
t.navService.redirectAfterLogin();
});
}
auth.service.ts
public login () {
return new Promise<any>((resolve, reject) => {
const client = new Auth0Cordova(auth0Config);
const options = {
scope: 'openid profile offline_access'
};
client.authorize(options, (err, authResult) => {
if(err) {
throw err;
}
this.setIdToken(authResult.idToken);
this.setAccessToken(authResult.accessToken);
const expiresAt = JSON.stringify((authResult.expiresIn * 1000) + new Date().getTime());
this.setStorageVariable('expires_at', expiresAt);
this.auth0.client.userInfo(this.accessToken, (err, profile) => {
if(err) {
throw err;
}
profile.user_metadata = profile.user_metadata || {};
this.setStorageVariable('profile', profile);
this.zone.run(() => {
this.user = profile;
resolve(profile);
}); // end zone run
}); // end userInfo
}); // end authorize
}); // end Promise
} // end login
(Let me know in comments if there could be a better practice)
See:
How to wait for a function to finish its execution in angular 2.?
javascript, promises, how to access variable this inside a then scope

Update you should be placing the redirection on success of authentication
public login () {
this.authService.login();
///////////////// remove it
}
Place it in the Authservice login() method
login(){
this.redirectAfterLogin ()
}
Or return a Boolean variable on from the login method in AuthService
login() :boolean {
//// your code
if(success) return true;
else return false;
}
In your NavService
public login () {
if(this.authService.login()){
this.redirectAfterLogin ();
}

Related

undefined var module.exports

For some reason, I can't get values returned from module.exports function from a separate custom module. I tried many ways from many sources from >10s researched posts. If you want to vote down, please read my bio or if you want to help I will be happy to accept your answer.
// restapi/index.js
module.exports = function gifs() {
giphy.search('Pokemon', function (err, res) {
return res.data[0];
});
}
// main server.js
var readapi = require('restapi')
console.log(readapi.gifs());
// Output:__________________
TypeError: readapi.gifs is not a function
You are exporting a function, not an object with a function and you are using a sync function (console.log) with an async operation.. it won't work.
You need to write it like this:
module.exports = function gifs(cb) {
giphy.search('Pokemon', function (err, res) {
if(err) { cb(err) }
else { cb(null, res.data[0]) }
});
}
----
var readapi = require('restapi')
readapi((err, data) => { console.log({err, data}) })
Remember the difference between:
module.export = {
hello: () => { console.log('world') }
}
// usage: require('./hello').hello()
module.export = () => { console.log('world') }
// usage: require('./hello')()
Try this code
module.exports.gifs = function gifs() {
return new Promise((resolve, reject) => {
giphy.search('Pokemon', function (err, res) {
if (err) reject(err);
else resolve(res.data[0]);
});
});
}
// main server.js
var readapi = require('restapi')
readapi.gifs().then(console.log);

I called then() on a TypeScript promise but it is still pending. Why is this? How can I get it to resolve?

Here is the index.ts script I am running (based on something I found on reddit):
const path = require("path");
const sql = require("mssql");
const config = require(path.resolve("./config.json"));
let db1;
const connect = () => {
return new Promise((resolve, reject) => {
db1 = new sql.ConnectionPool(config.db, err => {
if (err) {
console.error("Connection failed.", err);
reject(err);
} else {
console.log("Database pool #1 connected.");
resolve();
}
});
});
};
const selectProjects = async (name) => {
const query = `
select * from [Time].ProjectData where [Name] like concat('%', concat(#name, '%'))`;
const request = new sql.Request(db1);
const result = await request
.input("name", name)
.query(query);
return result.recordset;
};
module.exports = {
connect,
selectProjects
};
connect().then(function() {
console.log(selectProjects('General'));
}).catch(function(err) {
console.log(err);
});
When I run the script using node index (after compiling it of course), I get this in the console:
Database pool #1 connected.
Promise { <pending> }
And then the script hangs.
Apparently the await keyword creates an implicit promise; I had to change the last function call to:
connect().then(function() {
selectProjects('General').then(function(data) {
console.log(data);
});
}).catch(function(err) {
console.log(err);
});

Async-await not working as anticipated. Value is 'undefined' after using await

I'm using socket.io with node js. For the authentication, I'm using middleware in socket.io but the code is not waiting for the middleware to finish its work thus the value is 'undefined'.
Here is the main function.
module.exports = async (server) => {
const io = require('socket.io')(server);
io.on(CONNECTION, async function (socket) {
var email = await authenticateUser(io);
console.log(email); // 'undefined'
user = new User(email);
});
}
Middleware function
async function authenticateUser(io) {
io.use(async (socket, next) => {
const handshakeData = socket.handshake.query;
const token = handshakeData.token;
const Email = await Token.isValid(token);
console.log("Auth ---> " + Email); // here it is fine
return new Promise((res, rej) => {
if (Email) {
res(Email);
} else {
rej();
}
});
});
}
Authtentication function
exports.isValid = async (token) => {
try {
const decoded = jwt.verify(token, JWT_KEY);
console.log(decoded.email) // here it is fine
return decoded.email;
} catch (error) {
return false;
}
}
Thank you!
The promise you are creating inside authenticateUser is not visible to the caller since it is created inside the scope of the function you are passing to io.use().
Instead, try creating the promise one lexical level higher so that it is visible after you are finished with the socket.io event handler:
// middleware function
function authenticateUser(io) {
return new Promise((resolve, reject) => {
io.use(async (socket, next) => {
const handshakeData = socket.handshake.query;
const token = handshakeData.token;
const Email = await Token.isValid(token);
if (Email) {
resolve(Email);
} else {
reject(); // should probably put an error here
}
});
});
}

Angular2 view not updated after callback function

I'm using Meteor-Angular2 and slingshot package for uploading images to S3 storage. when returning from the function and assign to binded string, view not updated. (setTimout function is working and updating view, but uploader function not)
export class AdminComponent {
public urlVariable: string = "ynet.co.il";
constructor() {
this.uploader = new Slingshot.Upload("myFileUploads");
setTimeout(() => {
this.urlVariable = "View is updated";
}, 10000);
}
onFileDrop(file: File): void {
console.log('Got file2');
this.uploader.send(file, function (error, downloadUrl) {
if (error) {
// Log service detailed response
}
else {
this.urlVariable = "View not updated";
}
});
}
}
Use arrow functions (() =>) instead of function () to retain the scope of this.
this.uploader.send(file, (error, downloadUrl) => {
if (error) {
// Log service detailed response
}
else {
// now `this.` points to the current class instance
this.urlVariable = "View not updated";
}
});
https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Functions/Arrow_functions
this one is working for me: (narrow function+Ngzone)
this.uploader.send(file, (error, downloadUrl) => {
if (error) {
// Log service detailed response
}
else {
// now `this.` points to the current class instance
this._ngZone.run(() => {this.urlVariable = "View not updated"; });
}
});

how to return a data from http call in angular 2 when the call is success

Take this function as example:
getSessionInfo() {
this._http.get(someCorrectUrlHere)
// Don't know what this map function do
.map(res => res.json())
// Don't know what this subscribe function do
.subscribe(
data => {
if (data.response.statusCode === 200) {
** the data.response.data in this case is an object**
return data.response.data;
} else {
console.log("cant get session info");
}
},
err => console.log(err),
() => { }
);
}
What my understanding is, the return data.response.data will not actually return something when the getSessionInfo() is called.
For example, the this.session will still be undefined.
getSession() {
this.session = this.service.getSessionInfo();
}
What I want to do is, return the value data.response.data and assign it to this.session.
Note, they are in different class in Angular2 Project.
export class HeaderComponent {
service: ApiService;
session: Object;
constructor(service: ApiService) {
this.service = service;
this.getSession();
}
getSession() {
this.session = this.service.getSessionInfo();
// I expect this is the true value I expected, not undefined
console.log(this.session);
}
}
The ApiService class is in a different folder
#Injectable()
export class ApiService {
_http: Http;
regions: Object;
constructor(http: Http) {
this._http = http;
}
getSessionInfo() {
.......
}
}
I used to know they can do what I want using $q, $defer, but what should I do using Angular 2
Do return create either new Promise/Observable as you are going to use .subscribe over observable. So this._http.get(someCorrectUrlHere) promise from getSessionInfo method and then do have .then with Arrow function over getSessionInfo method.
getSessionInfo() {
//creating custom promise & then resolving and rejecting it on condition.
return new Promise((resolve, reject) =>{
this._http.get(someCorrectUrlHere)
.map(res => res.json())
.subscribe(
data => {
if (data.response.statusCode === 200) {
resolve(data.response.data); //returning data by resolving promise
} else {
console.log("cant get session info");
reject("Error occured");
}
},
err => {
console.log(err);
reject(err);
},
() => {}
);
});
}
Code
export class HeaderComponent {
service: ApiService;
session: Object;
constructor(service: ApiService) {
this.service = service;
this.getSession();
}
getSession() {
this.service.getSessionInfo().then(
//success function.
(session) => {
this.session = session;
console.log(session);
},
(error)=>{
//error function
});
}
}
You can convert Observable returned by Angular 2 http call to Promise if you are comfortable working with that
getSessionInfo() {
return this._http.get(someCorrectUrlHere).toPromise();
);
More about it in the official Angular docs here.
Or, you can try to do it Angular 2 way. Keeping your service as
getSessionInfo() {
this._http.get(someCorrectUrlHere)
.map(res => res.json())
}
and subscribing in your HeaderComponent
getSession() {
this.service.getSessionInfo().subscribe(
data => {
if (data.response.statusCode === 200) {
this.session = data.response.data;
console.log(this.session);
} else {
console.log("cant get session info");
}
},
err => console.log(err),
() => { }
);
}

Categories

Resources