as I understand it Angular http has 2 checks 'success and 'error'. Thats in terms of connecting to the service or not - so I have that in hand and thats my first check.
The issue I have is that the data in my JSON has a success state which informs me if the data it contains or has received from my form had any problems with it, in which case there will be an error object that I act on and display to the user.
I need to check for that value of success, but where is the best place to check for that?
Should I be doing it in the controller?
Without that data being correct theres nothing else for the page to do so it is effectively the first thing that needs to be done after the data is retrieved.
heres the basic controller layout
app.controller("dataCtrl", function ($scope, $http) {
$http.post('/getdata').success(function (data) {
$scope.businessData = data;
// Should I then be checking businessData.success at this level?
}).error(function () {
alert("Problem");
});
});
You can write something like this:
$http.post('/getdata').success(function (data) {
if (validate(data)) {
$scope.businessData = data;
} else {
$scop.buisnessDataError = {msg: 'smth bad happend'};
}
}).error(function () {..})
Otherwise, you can write your validator in Promise-like style and then just chain promises in such manner:
$http.post('/getdata').then(function (res) {
return validator(null, res.data);
}, function (err) {
return validator({msg: 'error'})
}).then(function (data) {
//proceed your data
}, function (err) {
alert(err.msg);
});
Where validator is:
var varlidator = function (err, data) {
return $q(function (resolve, reject) {
if (/*data is not valid*/ || err) {
reject(err);
} else {
resolve(data);
}
});
}
$q is a standard angulars implementation of Promises
Related
In my angularjs app I have the following code on button click:
if (!$scope.isChecked) {
$scope.getExistingName($scope.userName).then(function (data) {
$scope.userName = data;
});
}
//some processing code here then another promise
myService.save($scope.userName,otherparams).then(function (res) {
//route to page
}, function (err) {
});
The issue here is if $scope.isChecked is false, it goes inside the promise and since it takes time to resolve it comes out and goes to next line of code. Because of this $scope.userName is not updated and uses old values instead of the updated value returned.
Whats the best way to handle this?
You can use $q. First you have to inject $q in your angular controller.
//Create empty promise
var promise;
if (!$scope.isChecked) {
promise = $scope.getExistingName($scope.userName).then(function (data) {
$scope.userName = data;
});
}
// Wait or not for your promise result, depending if promise is undefined or not.
$q.all([promise]).then(function () {
//some processing code here then another promise
myService.save($scope.userName,otherparams).then(function (res) {
//route to page
}, function (err) {
});
});
If the myService.save need to wait for the $scope.getExistingName promise just compute that operation inside the "then" statement.
if (!$scope.isChecked) {
$scope.getExistingName($scope.userName).then(function (data) {
$scope.userName = data;
myService.save($scope.userName,otherparams).then(function (res) {
//route to page
}, function (err) {
});
});
}
//some processing code here then another promise
I've only recently looked at promises (JS not being my forte) and I'm not sure what the proper way to do this is. Promises are supposed to prevent right-drifting code but when I end up with somewhat complex logic I end up nested far too deep anyway, so I'm convinced I'm doing it wrong.
If I'm returning both successes and failures as json values, and I want to handle malformed json as well, I immediately think to do something like this:
fetch('json').then(function (result) {
return result.json();
}).catch(function (result) {
console.error("Json parse failed!");
console.error(result.text);
}).then(function (wat) {
// if (!result.ok) { throw...
}).catch(function (wat) {
// Catch http error codes and log the json.errormessage
});
Of course, this won't work. This is stereotypical synchronous code. But it's the first thing that comes to mind. Problems I can see:
How do I get both the response and the json output?
How do I get separate control flow for errors and successes?
How do I catch a json parse error on both types of response?
My best attempt involves nesting to the point where I might as well be using callbacks, and it doesn't work in the end because I still haven't solved any of the above problems:
fetch('json').then(function (response) {
if (!response.ok) {
throw response;
}
}).then(
function (response) {
response.json().then(function (data) {
console.log(data);
});
},
function (response) {
response.json().then(function (data) {
console.error(data.errormessage);
});
}
).catch(function () {
console.error("Json parse failed!");
// Where's my response????
});
What's the "Right" way to do this? (Or at least less wrong)
If you want to call response.json() anyway (for successful and failed response) and want to use the response together will the response data. Use Promise.all:
fetch('json')
.then(response => Promise.all([response, response.json()]))
.then(([response, data]) => {
if (!response.ok) {
console.error(data.errormessage);
} else {
console.log(data);
}
})
.catch(err => {
if (/* if http error */) {
console.error('Http error');
} else if (/* if json parse error */)
console.error('Json parse failed');
} else {
console.error('Unknown error: ' + err);
}
});
You shouldn't use exceptions for control flow in Promises any more than you should when not using Promises. That's why fetch itself doesn't just reject the promise for status codes other than 200.
Here's one suggestion, but the answer will necessarily depend on your specific needs.
fetch('json').then(function (response) {
if (!response.ok) {
response.json().then(function (data) {
console.error(data.errorMessage);
});
return ...;
}
return response.json().catch(function () {
console.error("Json parse failed!");
return ...;
});
}).catch(function (e) {
console.error(e);
return ...;
});
I am trying to delete a post from a list. The delete function is performing by passing serially to a delete function showed below.
$scope.go = function(ref) {
$http.get("api/phone_recev.php?id="+ref)
.success(function (data) { });
}
After performing the function, I need to reload the http.get request which used for listing the list.
$http.get("api/phone_accept.php")
.then(function (response) { });
Once the function performed. The entire list will reload with new updated list. Is there any way to do this thing.
Try this
$scope.go = function(ref) {
$http.get("api/phone_recev.php?id="+ref)
.success(function (data) {
//on success of first function it will call
$http.get("api/phone_accept.php")
.then(function (response) {
});
});
}
function list_data() {
$http.get("api/phone_accept.php")
.then(function (response) {
console.log('listing');
});
}
$scope.go = function(ref) {
$http.get("api/phone_recev.php?id="+ref)
.success(function (data) {
// call function to do listing
list_data();
});
}
Like what #sudheesh Singanamalla says by calling the same http.get request again inside function resolved my problem.
$scope.go = function(ref) {
$http.get("api/phone_recev.php?id="+ref).success(function (data) {
//same function goes here will solve the problem.
});}
});
You can use $q - A service that helps you run functions asynchronously, and use their return values (or exceptions) when they are done processing.
https://docs.angularjs.org/api/ng/service/$q
Inside some service.
app.factory('SomeService', function ($http, $q) {
return {
getData : function() {
// the $http API is based on the deferred/promise APIs exposed by the $q service
// so it returns a promise for us by default
return $http.get("api/phone_recev.php?id="+ref)
.then(function(response) {
if (typeof response.data === 'object') {
return response.data;
} else {
// invalid response
return $q.reject(response.data);
}
}, function(response) {
// something went wrong
return $q.reject(response.data);
});
}
};
});
function somewhere in controller
var makePromiseWithData = function() {
// This service's function returns a promise, but we'll deal with that shortly
SomeService.getData()
// then() called when gets back
.then(function(data) {
// promise fulfilled
// something
}, function(error) {
// promise rejected, could log the error with: console.log('error', error);
//some code
});
};
I am trying to write a promise function using Bluebird library for nodejs. I want to return 2 variables from my function.
I want the first function to return immediately and the second to complete its own promise chain before returning.
function mainfunction() {
return callHelperfunction()
.then(function (data) {
//do something with data
//send 200 Ok to user
})
.then(function (data2) {
//wait for response from startthisfunction here
})
.catch(function (err) {
//handle errors
});
}
function callHelperfunction() {
return anotherHelperFunction()
.then(function (data) {
return data;
return startthisfunction(data)
.then(function () {
//do something more!
})
});
}
Just like regular functions only have one return value, similarly promises only resolve with one value since it's the same analogy.
Just like with regular functions, you can return a composite value from a promise, you can also consume it using .spread for ease if you return an array:
Promise.resolve().then(function(el){
return [Promise.resolve(1), Promise.delay(1000).return(2));
}).spread(function(val1, val2){
// two values can be accessed here
console.log(val1, val2); // 1, 2
});
The only thing that appears to be wrong is the expectation that do something with data; send 200 Ok to user; should be performed in mainfunction(), part way through the promise chain in callHelperfunction().
This can be overcome in a number of ways. Here's a couple :
1. Move do something with data; send 200 Ok to user; into callHelperfunction()
function mainfunction() {
return callHelperfunction())
.catch(function (err) {
//handle errors
});
}
function callHelperfunction() {
return anotherHelperFunction()
.then(function (data1) {
//do something with data
//send 200 Ok to user
return startthisfunction(data1)
.then(function (data2) {
//wait for response from startthisfunction here
//do something more!
});
});
}
2. Dispense with callHelperfunction() altogether and do everything in mainfunction()
function mainfunction() {
return anotherHelperFunction()
.then(function (data1) {
//do something with data1
//send 200 Ok to user
return startthisfunction(data1);
})
.then(function (data2) {
//wait for response from startthisfunction here
})
.catch(function (err) {
//handle errors
});
}
I have a problem with the following code:
initPromise = $q.all(arrayOfPromises)
.then(function () {
return $scope.methodWhichReturnsPromise()
.then(function (data) {
console.log("report data");
return data;
});
});
if ($scope.showCompare) {
initPromise
.then(function () {
return $q.all(anotherArrayOfPromises);
})
.then(function () {
return aMethodWhichReturnsAPromise().then(function () {
console.log("compare report data");
});
});
}
initPromise
.then(function () {
console.log("generate view data");
})
.finally(function () {
console.log("finally");
});
I'm loading a bunch of async data when loading a controller based on route parameters. And if the flag showCompare is there, I want to load something in between. But the order of the console.log messages is the following:
report data
generate view data
finally
compare report data
I was expecting that compare report data would show up exactly in the same order it was written in the code.
What am I doing wrong?
You are adding two distinct handler on the initPromise, instead of chaining all .then() calls. To do so, you would need to use
if ($scope.showCompare) {
initPromise = initPromise.then(…);
}