Promises in angularjs controller - how to implement - javascript

I am trying to implement a basic function using promises in one of my controllers just so I can ensure it is working correctly before adding in more complex functionality. I am getting a "TypeError: undefined is not a function" on the ".then(function(data){" in the lockPromise method.
Function called from view
$scope.lockPromise = function(fieldId) {
$scope.getLockMessage2(fieldId).getWeather()
.then(function(data) {
if (data === "returned SUCCESS info") {
alert("data is good");
} else {
alert("FAILED");
}
}, function(error) {
alert(error);
});
};
Second function in ctrl
$scope.getLockMessage2 = function(fieldId) {
return{
getWeather: function() {
return $http.get('/api/getData')
.then(function(response) {
if (typeof response.data === "string") {
return response.data;
} else {
return $q.reject(response.data);
}
}, function(response) {
return $q.reject(response.data);
});
}
};
};
API GET
[Route("api/getData")]
public HttpResponseMessage GetData()
{
string data = JsonConvert.SerializeObject("returned SUCCESS info");
return new HttpResponseMessage
{
Content = new StringContent(data, Encoding.UTF8, "application/json")
};
}
EDIT 1:
code updated to reflect comments

Change
$scope.getLockMessage2(fieldId).then
to
$scope.getLockMessage2(fieldId).getWeather().then

Your $scope.getLockMessage2 return an object, not function.
I think the code should be (not tested):
$scope.lockPromise = function(fieldId) {
$scope.getLockMessage2(fieldId).getWeather()
.then(function(data) {
if (data === "good") {
alert("data is good");
} else {
alert("FAILED");
}
}, function(error) {
alert(error);
});
};

Related

Object is possibly undefined in TypeScript

I did use sfDoc !== undefined, but still I'm getting the error of object is possibly undefined. Am I doing anything wrong here?
return database.runTransaction(function (transaction) {
return transaction.get(sfDocRef).then(sfDoc => {
if (!sfDoc.exists) {
throw "Document does not exist!";
}
if (sfDoc !== undefined) {
var usedCount = sfDoc.data().usedCount + 1;
transaction.update(sfDocRef, { usedCount: usedCount });
}
return transaction;
});
}).then(function () {
console.log("Tag field changed!");
return true;
}).catch(function (error) {
console.log("Error in changing Tag field: ", error);
return false;
});
Try this example. Check for the sfDoc and return transaction.update, So that then wait to resolve the promise. According to document, you don not has to check for sfDoc. It will be always defined.
return database
.runTransaction(function (transaction) {
return transaction.get(sfDocRef).then((sfDoc) => {
if (sfDoc && sfDoc.exists) {
var usedCount = sfDoc.data().usedCount + 1;
return transaction.update(sfDocRef, { usedCount: usedCount });
} else {
throw "Document does not exist!";
}
});
})
.then(function () {
console.log("Tag field changed!");
return true;
})
.catch(function (error) {
console.log("Error in changing Tag field: ", error);
return false;
});

use of then / catch in $http call in angular

I my Node backend have the following end-point:
usersRoute.get('/get', function(req, res) {
//If no date was passed in - just use todays date
var date = req.query.date || dateFormat(new Date(), 'yyyy-mm-dd'),
search = req.query.search;
users.getAllUsers(date, search)
.then(function(results) {
res.json(results);
}, function(err) {
res.status(500).json({
success: false,
message: 'Server error.',
data: []
});
});
});
I have changed my sql table name to something else to trigger the function(err){} part
When I use this in my service it looks like this:
function getUsers(date, search) {
return $http.get('/api/users/get', {
params: {
date: UtilsService.formatDate(date),
search: search
}
})
.then(getData)
.catch(handleErr);
function getData(response) {
return response.data;
}
function handleErr(err) {
LoggerService.error('Could not retrieve users.', err ,'Ooops');
}
}
Knowing the server will return an http status code 500, I thought it would go right to the catch block. But it also returns the data /which is undefined in the then block
I use my service in my controller like this:
function getUsers(date, search) {
isAdmin();
vm.loading = true;
vm.filteredUsers = [];
return UsersService.getUsers(date, search).then(function(data) {
vm.loading = false;
allUsers = data || [];
vm.filteredUsers = allUsers.slice(0, 50);
vm.distribution = UsersService.getDistribution(allUsers);
return vm.filteredUsers;
});
}
My problem is, since the then part is triggered in my service. I'm trying to slice undefined
My question is: What are som best practices when it comes to this sort of pattern.
The problem is that your catching the error from your API and then returning the promise created by .catch.
Quick example
promise.then(function(data) {
throw 'Some error';
}).catch(function (err) {
console.log(err) // will output 'Some error'
}).then(function () {
// This will run even though we have a catch before
});
So how can we prevent the .then it's easy we throw an error inside the .catch
promise.then(function(data) {
throw 'Some error';
}).catch(function (err) {
console.log(err) // will output 'Some error'
throw 'You shall not pass'
}).then(function () {
// This will not run
});
So in your case you have two options, one throw an error as I said or two inject the $q service into your service:
function getUsers(date, search) {
return $http.get('/api/users/get', {
params: {
date: UtilsService.formatDate(date),
search: search
}
})
.then(getData)
.catch(handleErr);
function getData(response) {
return response.data;
}
function handleErr(err) {
LoggerService.error('Could not retrieve users.', err ,'Ooops');
return $q.reject(err);
}
}
You could do something like that
function getUsers(date, search, cb) {
return $http.get('/api/users/get', {
params: {
date: UtilsService.formatDate(date),
search: search
}
})
.then(cb)
.catch(handleErr);
function handleErr(err) {
LoggerService.error('Could not retrieve users.', err ,'Ooops');
}
}
And then in your controller
UsersService.getUsers(date, search, function(data) {
vm.loading = false;
allUsers = data || [];
vm.filteredUsers = allUsers.slice(0, 50);
vm.distribution = UsersService.getDistribution(allUsers);
});

How to return a boolean from an angular factory

I wrote a generic crud factory that is proving rather useful so far, the only problem is, when I go to use the service and check the result the value is not retaining the boolean true. I believe this is because javascript return acts on a per function basis, but I am not sure how to manuver the boolean out properly. Any ideas?
module.factory('crud', function ($http, API_CONFIG) {
return {
delete: function ($index, $scope, id, collection) {
$http({
url: API_CONFIG.url + collection + "/" + id,
method: 'DELETE',
headers: { "Content-Type": "application/json;charset=utf-8" }
}).success(function (result) {
console.log(result);
$scope.countries.splice($index, 1);
return true;
}).error(function () {
console.log("error");
});
},
update: function ($index, $scope, id, collection) {
console.log("update");
console.log(id);
console.log(collection);
},
create :function(model, collection) {
$http.post(
API_CONFIG.url + collection,
JSON.stringify(model),
{
headers: {
'Content-Type': 'application/json'
}
}
).success(function (data) {
console.log("model sent");
return true;
}).error(function () {
console.log("error");
});;
}
};
});
module.run(function ($rootScope, crud) {
$rootScope.appData = crud;
});
Then used like so in controller:
var result = $scope.appData.create(country, "collection");
if (result === true) {
You are using return inside a callback function that is asynchronous. Therefore the code that is executed afterwards should also by asynchronous. Try passing an additional function to create that will be executed on success. For example:
create: function(model, collection, callback) {
$http.post(...)
.success(function(data) { callback(data, true); })
.error(function(data) { callback(data, false); });
}
You can then use this like:
appData.create(model, collection, function(data, success) {
if(success === true) {
...
} else {
...
}
}
You need to return the promise return $http on the factory and them do something like this:
$scope.appData.create(country, "collection").then(function() {
// like a result = true;
}, function() {
// like a result = false;
});

How do I pass data from angular post to web api post

I have an angular post method through which I want to pass data to web api post but doesn't seem to work.
What could I be doing wrong?
customerPersistenceService.js
var customerPersistenceService = function ($http, $q) {
return {
save: function(customer) {
var deferred = $q.defer();
$http.post("/api/customers", customer)
.success(deferred.resolve)
.error(deferred.reject);
return deferred.promise;
},
update: function(customer) {
var deferred = $q.defer();
$http.put("/api/customers/{id}" + customer.id, customer)
.success(deferred.resolve)
.error(deferred.reject);
return deferred.promise;
}
};
};
customerEditCtrl.js
function customerEditCtr($stateParams, $location, customerPersistenceService) {
var vm = this;
vm.editableCustomer = {};
vm.selectedCustomerId = $stateParams.id;
customerPersistenceService.getById(vm.selectedCustomerId).then(
function (customer) {
vm.editableCustomer = customer;
});
};
vm.saveCommand = function () {
if (saveCustomer) {
var customer = vm.editableCustomer;
customer.id = vm.selectedCustomerId;
if (customer.id !== 0) {
customerPersistenceService.update(customer).then(
function (result) {
return result.data;
});
} else {
customerPersistenceService.save(customer).then(
function (result) {
return result.data;
});
}
}
};
};
In the CustomerAPIController.cs my methods look like these:
[HttpPost]
public HttpResponseMessage Post([FromBody]Customer newCustomer)
{
try
{
if (ModelState.IsValid)
{
_customerService.AddNewCustomer(newCustomer);
return Request.CreateResponse(HttpStatusCode.Created, newCustomer);
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
}
catch (Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
}
}
[HttpPut]
public HttpResponseMessage Put(int id, [FromBody]Customer editableCustomer)
{
if (!ModelState.IsValid)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
if (id != editableCustomer.Id)
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
try
{
_customerService.UpdateCustomer(editableCustomer);
return Request.CreateResponse(HttpStatusCode.OK, "{success:'true', verb:'PUT'}");
}
catch (DbUpdateConcurrencyException ex)
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
}
}
Update:
After some investigation, I realise the vm.editableCustomer seems to contain an array of all customer objects making it hard to pass to the Web API POST.
I fail to understand how this object gets assigned with all customer objects.
There is a clear error:
$http.put("/api/customers/{id}" + customer.id, customer)
This will try to PUT to an url like this:
http://yoursite/api/customers/{id}927
You need to remove the {id} part, so that your url is correct:
http://yoursite/api/customers/927
The segment enclosed in braces only exists in the server side route template, and it's used to extract the parameter from the incoming URI.

Factory return returning function, not product of function

I have implemented a promise inside the factory which seems to work. However I seem to be returning the function ... not the product of the function. If I console log I am seeing the full function printed out in the console instead of the data.
Have I messed up the way the data is return?
Object {data: function} <-- from console log
latestScores.factory('importIO', function($q) {
return {
data: function(){
var deferred = $q.defer()
setTimeout(function() {
var io2 = new importio("xxx", "xxx", "import.io");
io2.connect(function(connected) {
if (!connected) {
console.error("Unable to connect");
return;
}
var data;
var callback = function(finished, message) {
if (message.type == "DISCONNECT") {
console.error("The query was cancelled as the client was disconnected");
deferred.reject(new Error('No name specified for greeting'))
}
if (message.type == "MESSAGE") {
if (message.data.hasOwnProperty("errorType")) {
console.error("Got an error!", message.data);
} else {
data = message.data.results;
deferred.resolve(data)
}
}
if (finished) {
data = message.data.results;
deferred.resolve(data)
}
};
io2.query({
"connectorGuids": [
"xxx"
],
}, callback);
});
}, delay)
return deferred.promise
}
}
});
latestScores.controller('ScoresController', function($scope, importIO) {
$scope.liveScores = importIO.data;
console.log($scope.liveScores); /* returns a console log of function not data */
});
Thanks for your time.
You are assigning the function to $scope.liveScores not the result.
You make use of promises like this:
importIO.data().then(function(result){
$scope.liveScores = result;
console.log($scope.liveScores);
});
This means you execute data function and then, after the method "data" is complete, you assign the result to liveScores.
Since importIO.data() is a function..try this:
latestScores.controller('ScoresController', function($scope, importIO) {
importIO.data().then(function (result) {
$scope.liveScores = result;
console.log($scope.liveScores);
});

Categories