Using promises with AngularJS - javascript

I have this service
service.getCurrentUser = function () {
var def = $q.defer(); 
if (service.user == null)
{
$http.get("./api/GetCurrentUser/")
.success(function(data) { 
service.user=data; 
def.resolve(data); 
}) 
.error(function() { 
def.reject("Failed to get user"); 
}); 
}
else
def.resolve(service.user);
return def.promise;
} 
in my controller I want to call this and wait for return then if the user is in a certain group run other code
How do I write it so it uses the promise returned by the service

The promise implementation can be like:
service.getCurrentUser = function () {
return new Promise((resolve,reject)=>{
if (service.user == null) {
$http.get("./api/GetCurrentUser/")
.success(function (data) {
service.user = data;
resolve(data);
})
.error(function () {
reject("Failed to get user");
});
}else{
resolve(service.user);
}
});
}
You can call it as:
service.getCurrentUser()
.then(user => {
console.log('user', user);
})
.catch(error => {
console.log('error', error);
});

Related

How can return false value promise method in node if array is empty and vise versa

i was trying out promise code but it always returns me resolve even if the user does not exist in the database
can anyone help me fix my code and the return statement
in the return function the the second console log is only working.
here is my code
Api Call
const email = 't#t.com';
const request = require('request');
function IsUserExists(email, kc_accessToken) {
let url = `${path}/users?email=${email}`;
return new Promise(function (resolve, reject) {
request(
{
url: url,
headers: {
'content-type': 'application/json',
authorization: `Bearer ${kc_accessToken}`,
},
},
function (error, response, body) {
if (error) {
console.log('some error occured');
}
if (response.body.length > 0) {
console.log('User Exist');
return resolve();
}
console.log('Does not Exist');
return reject();
}
);
});
}
Function Call
http
.createServer(function Test() {
getAccessToken()
.then(function (response) {
kc_accessToken = response.data.access_token;
IsUserExists(email, kc_accessToken).then((resp) => {
if (resp) {
console.log('Do Not Create');
} else if (!resp) {
console.log('Creat a new User');
}
});
})
.catch(function (error) {
// handle error
console.log(error);
})
.then(function () {
// always executed
});
})
.listen(8081);
When Provided user email which exist ( t#t.com )
When Provided user email which does not exist( 09#t.com )
I need to create a new answer for example to you question in comments.
Now, you go into the reject function so you need to handle this rejection in the outside.
if (response.body.length > 0) {
console.log('User Exist');
return resolve();
}
console.log('Does not Exist');
return reject(); // -> Now here you are
You need add .catch function after IsUserExists.then().
It will be IsUserExists.then().catch()
http.createServer(function Test() {
getAccessToken()
.then(function (response) {
kc_accessToken = response.data.access_token;
// here you only accept the data from resolve in Promise
// so you need to add .catch function to handle the rejection.
IsUserExists(email, kc_accessToken).then((resp) => {
if (resp) {
console.log('Do Not Create');
} else if (!resp) {
console.log('Creat a new User');
}
}).catch((error) => {
console.log(error)
});
})
.catch(function (error) {
// handle error
console.log(error);
})
.then(function () {
// always executed
});
})
.listen(8081);
By the way, you could add parameter in rejection function like reject(new Error("user not found)).
Then in the outside, you can get this rejection message.

Fetch then after catch still be called even be catched [duplicate]

This question already has answers here:
Chained promises not passing on rejection
(4 answers)
Closed 3 years ago.
I want to return a fetch promise to upper layer to use, but I found even this fetch promise fail (be catched), upper layer's then still be called. Is it possible "upper layer's then" only be called when fetch success?
export default function request(url, options) {
.......
return fetch(url, options)
.then(checkStatus)
.then(parseJSON)
.then(data => {
// debugPrint("receive response" + JSON.stringify(data));
if (+data.status.code !== 200) {
message.error(data.status.message || "please retry");
}
return data;
})
.catch(err => {
message.error(err.toString() || "please retry");
return err;
});
}
// then I call request this way:
export function userLogin(account) {
return request(`${domain}/signin/get_accesstoken`, {
method: "POST"
}).then(data => {
// even catch be called, this then still be called. Is it possible only call this then when catch not be called ?
do something;
return data;
});
}
Second edit:
I try to return a promise in then, but look like it is not a promise be returned, I don't know why.
export default function request(url, options) {
.......
return fetch(url, options)
.then(checkStatus)
.then(parseJSON)
.then(data => {
// debugPrint("receive response" + JSON.stringify(data));
if (+data.status.code !== 200) {
message.error(data.status.message || "please retry");
}
return new Promise(resolve=>{
resolve(data)
});
})
.catch(err => {
message.error(err.toString() || "please retry");
return new Promise((resolve, reject)=>{
reject(err)
});
});
}
Edit third:
export default function request(url, options) {
.......
return fetch(url, options)
.then(checkStatus)
.then(parseJSON)
.then(data => {
// debugPrint("receive response" + JSON.stringify(data));
if (+data.status.code !== 200) {
message.error(data.status.message || "please retry");
}
return data;
})
.catch(err => {
message.error(err.toString() || "please retry");
return;
});
}
// then I call request this way:
export function userLogin(account) {
return request(`${domain}/signin/get_accesstoken`, {
method: "POST"
}).then(data => {
// add this
if (!data) {
return
}
do something;
return data;
});
}
if you want to call your upper layer's then only in case of success then throw some error in catch block of fetch instead of returning err.
export default function request(url, options) {
.......
return fetch(url, options)
.then(checkStatus)
.then(parseJSON)
.then(data => {
// debugPrint("receive response" + JSON.stringify(data));
if (+data.status.code !== 200) {
message.error(data.status.message || "please retry");
}
return data;
})
.catch(err => {
message.error(err.toString() || "please retry");
throw new Error('fetch failed'); // throw error
});
}

How To: correctly chain AngularJS async calls (AngularJs 1.7.5)

Recently started thinking that it was time to do a massive update to my logical operations, and part of that is the proper chaining of Angular JS asynchronous promise calls. Given the following code, how would I re-write it to be a proper chaining of two separate methods? (Yes, I've seen other posts about this, but they all deal with other versions of Angular, or other syntaxes, and I'm looking for something more up-to-date.)
vm.functionName = (
function() {
vm.processing = true;
api.promise1({ Id: vm.Id })
.then(
function(result) {
if (result.error) {
notificationService.danger("<h5>An error occurred.</h5><h6>Details: {0}</h6>".format(result.error));
} else {
api.promise2({ param: vm.param })
.then(
function(result2) {
if (result2.error) {
notificationService.danger("<h5>An error occurred.</h5><h6>Details: {0}</h6>".format(result2.error));
} else {
vm.data = result2.data;
notificationService.success("<h5>Operation successful!.</h5>");
}
vm.processing = false;
}
)
.catch(
function (err) {
console.error(err);
notificationService.danger("<h5>An error occurred.</h5><h6>Details: {0}</h6>".format(err.statusText));
vm.processing = false;
}
);
}
}
)
.catch(
function (err) {
console.error(err);
notificationService.danger("<h5>An error occurred.</h5><h6>Details: {0}</h6>".format(err.statusText));
vm.processing = false;
}
);
}
);
Logically, my brain tells me that I should be able to do something like this:
vm.functionName = (
function() {
vm.processing = true;
vm.promise1()
.then(
vm.promise2()
.then(
notificationService.success("<h5>Operation successful!.</h5>");
vm.processing = false;
);
);
);
}
);
vm.promise1 = (
function() {
api.promise1({ Id: vm.Id })
.then(
function(result) {
if (result.error) {
notificationService.danger("<h5>An error occurred.</h5><h6>Details: {0}</h6>".format(result.error));
}
}
)
.catch(
function (err) {
console.error(err);
notificationService.danger("<h5>An error occurred.</h5><h6>Details: {0}</h6>".format(err.statusText));
}
);
}
);
vm.promise2 = (
function() {
api.promise2({ param: vm.param })
.then(
function(result) {
if (result.error) {
notificationService.danger("<h5>An error occurred.</h5><h6>Details: {0}</h6>".format(result.error));
} else {
vm.data = result2.data;
}
}
)
.catch(
function (err) {
console.error(err);
notificationService.danger("<h5>An error occurred.</h5><h6>Details: {0}</h6>".format(err.statusText));
}
);
}
);
Update:
the "api...." calls above call to my service.js layer, where methods exist like such:
promise1: function (params, error) {
return $http
.post("/C#Controller/Method1", params)
.then(handleSuccess)
.catch(function (e) {
handleError(e, error);
});
},
promise2: function (params, error) {
return $http
.post("/C#Controller/Method2", params)
.then(handleSuccess)
.catch(function (e) {
handleError(e, error);
});
},
Updated, per Pop-A-Stash's ideas, as now implemented:
//#region Api Calls and Helper
function apiCallOne() {
return api.promise1({ Id: vm.Id });
}
function apiCallTwo() {
return api.promise2({param: vm.param });
}
function handleApiCallError(resultOrError, ngModelToSet) {
var errMsg = resultOrError.statusText === undefined ? resultOrError.error === undefined ? "Unknown Error" : resultOrError.error : resultOrError.statusText;
notificationService.danger("<h5>An error occurred.</h5><h6>Details: {0}</h6>".format(errMsg));
//This allows updating things like variables and ng-model goodies, via an inset function.
if (ngModelToSet) {
ngModelToSet();
}
}
//#endregion
//#region Initialization
function init() {
vm.pgLoaded = false;
apiCallOne()
.then(
function(result) {
if (!result.error) {
vm.data = result.data;
vm.pgLoaded = true;
} else {
handleApiCallError(result, function() { vm.pgLoaded = true; });
}
}
)
.catch(function(errorOne) { handleApiCallError(errorOne, function() { vm.pgLoaded = true; }); });
}
init();
//#endregion
You could shorten your code significantly using recursion to call the next promise in an array of objects containing promises and their parameters using something similar to this:
function runPromises(promises) {
var first = promises.shift();
first.function(first.params).then(function(resp) {
if (promises.length > 1) {
runPromises(promises);
}
}).catch(function (error) {
handleError(error);
});
}
with an initial array of something like this:
var promises = [
{
function: promise1,
params: any
},
{
function: promise2,
params: any
}
];
If each promise response requires individual handling you could add a callback to be fired after the promise is resolved for each promise.
If you want to chain them in a specific order, then you are already doing it correctly. However I see some code duplication that could be cleaned up:
vm.apiCallOne = apiCallOne;
vm.apiCallTwo = apiCallTwo;
vm.runChainedCalls = runChainedCalls;
function runChainedCalls() {
vm.processing = true;
vm.apiCallOne()
.then(function(result1) {
if(!result1.error) {
vm.apiCallTwo().then(function(result2) {
if(!result2.error) {
notificationService.success("<h5>Operation successful!.</h5>");
vm.data = result2.data;
vm.processing = false;
}
else {
handleError(result2);
}
})
.catch(function(errorTwo) {
handleError(errorTwo)
});
}
else {
handleError(result1);
}
})
.catch(function(errorOne) {
handleError(errorOne);
});
}
function apiCallOne(){
return api.callOne(param); //don't forget to return the promise object
};
function apiCallTwo() {
return api.callTwo(param); //don't forget to return the promise object
};
function handleError(resultOrError) {
notificationService.danger("<h5>An error occurred.</h5><h6>Details: {0}</h6>".format(resultOrError.statusText));
vm.processing = false;
}
You only need one .then() and .catch() for each call in your controller. Anymore than that is code duplication.
If you want to run them concurrently and don't care about order, you would use the $q.all() function to run them at the same time:
function runConcurrentCalls() {
$q.all([api.callOne(param), api.callTwo(param)]).then(function(responseArray) {
// responseArray contains array of both call responses
console.log(responseArray[0]);
console.log(responseArray[1]);
})
.catch(function() {
//something went wrong with one or both calls
});
}

Again about async/await in javascript

My function looks like this now:
var GetImages = async() => {
var images_array = [];
await request ({
url: `https://api.tumblr.com/v2/blog/nameblog/posts?api_key=${process.env.TUMBLR_KEY}&type=photo`,
json: true
}, (error, response, body) => {
if(error){
console.log('Unable to connect');
}else if(body.meta.status === "ZERO_RESULTS"){
console.log('Uable to find that address.');
}else if(body.meta.status === 200){
body.response.posts.forEach(function(obj) {
obj.photos.forEach(function(photo) {
if(photo.original_size.width>photo.original_size.height){
images_array.push(photo.original_size.url);
console.log("dawdaw");
}
});
});
//callback(images_array);
}
});
return images_array;
}
I have no idea, how return my array after i'll fill it with values. With callback it works fine, but i wanna do it with async/await methid in right way. Thank you for help.
create method to return promise for request and use that method with await
requestPromise = () => {
return new Promise(function(resolve, reject) {
request({
url: `https://api.tumblr.com/v2/blog/nameblog/posts?api_key=${process.env.TUMBLR_KEY}&type=photo`,
json: true
}, (error, response, body) => {
if (error) {
console.log('Unable to connect');
reject();
} else if (body.meta.status === "ZERO_RESULTS") {
console.log('Uable to find that address.');
reject();
} else if (body.meta.status === 200) {
body.response.posts.forEach(function(obj) {
obj.photos.forEach(function(photo) {
if (photo.original_size.width > photo.original_size.height) {
images_array.push(photo.original_size.url);
console.log("dawdaw");
}
});
});
resolve(images_array)
}
});
});
}
var GetImages = async() => {
try
{
images = await requestPromise();
return images;
}
catch(e){return [];}
}

function returns a promise reject when resolved

I have a angularjs controller and factory.
So my purpose is to manage all the message errors depending of the promise result. That means to receive in the controller a reject after checking some bad values in the resolve factory function.
I'm trying this way but it doesn't work:
factory.js
var mediaRecent;
function getMediaByUserName(user) {
return $http.get('https://www.instagram.com/' + user + '/media')
.then(function (response) {
if (response.data.items.length === 0) {
// I want here to cause a reject in the controller function
return new Error('This user is not public');
}
mediaRecent = response.data.items;
})
.catch(function (error) {
return new Error('There was a problem looking to that user');
});
}
controller.js
instagramFactory.getMediaByUserName(vm.name)
.then(function () {
$state.go('instagramMediaRecent');
})
.catch(function (error) {
vm.error = error.message;
});
var mediaRecent;
function getMediaByUserName(user) {
return $http.get('https://www.instagram.com/' + user + '/media')
.then(function (response) {
if (response.data.items.length === 0) {
// go to catch() from here
return $q.reject(new Error('This user is not public'));
}
mediaRecent = response.data.items;
})
.catch(function (error) {
return new Error('There was a problem looking to that user');
});
}
Actually you called promise twice. So you can call it only in Controller or Factory.
Simple way
Factory:
function getMediaByUserName(user) {
return $http.get('https://www.instagram.com/' + user + '/media');
}
Controller:
instagramFactory.getMediaByUserName(vm.name)
.then(function () {
if (response.data.items.length === 0) {
// I want here to cause a reject in the controller function
return new Error('This user is not public');
}
var mediaRecent = response.data.items;
$state.go('instagramMediaRecent');
})
.catch(function (error) {
vm.error = new Error('There was a problem looking to that user');
});

Categories

Resources