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

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.

Related

$q and resolving promises in Angular

I am not sure how to go about returning the promise. I have tried to return the result in a nested method but would prefer to return the result in two different methods as shown afterwards:
$scope.relatedContacts = function (accountId) {
if (!lodash.isNil(accountId)) {
try {
return restangular.one('user')
.one('contactimages')
.get({ 'mappedRelatedContactsPath': $scope.mappedRelatedContactsPath, "account": accountId })
.then(function (response) {
return response.data;});
}
}
Would prefer to fix the below example:
$scope.relatedContacts = function (accountId) {
if (!lodash.isNil(accountId)) {
try {
var deferred = $q.defer();
return restangular.one('user')
.one('contactimages')
.get({ 'mappedRelatedContactsPath': $scope.mappedRelatedContactsPath, "account": accountId })
return deferred.promise;
}
catch (err) {
$scope.contactsPopulated = false;
}
}
}
$scope.relatedContacts().then(function (response) {
//Some logic here
}
Currently I am getting : "TypeError: Cannot read property 'then' of undefined
"
Thanks all
First of all, remember about consistency. The isNil if makes your function not returning anything in some cases (you will get TypeError: Cannot read property 'then' of undefined " error when accountId is not provided.
You have two ways to solve your problem.
First way:
$scope.relatedContacts = function (accountId) {
return $q(function(resolve, reject) {
if (!lodash.isNil(accountId)) {
try {
return restangular.one('user')
.one('contactimages')
.get({ 'mappedRelatedContactsPath': $scope.mappedRelatedContactsPath, "account": accountId })
.then(function(response) {
resolve(response.data)
}, reject);
}
catch (err) {
$scope.contactsPopulated = false;
reject(err);
}
}
});
};
The second way (using defer).
$scope.relatedContacts = function (accountId) {
var def = $q.defer();
if (!lodash.isNil(accountId)) {
try {
restangular.one('user')
.one('contactimages')
.get({ 'mappedRelatedContactsPath': $scope.mappedRelatedContactsPath, "account": accountId })
.then(function(response) {
def.resolve(response.data)
}, def.reject);
}
catch (err) {
$scope.contactsPopulated = false;
def.reject(err);
}
}
return def;
};
You should check official reference about $q service:
https://docs.angularjs.org/api/ng/service/$q
There are numerous examples of typical promise usages.
This is what I used to return the value and add additional method to deal with the response.
$scope.relatedContacts = function (accountId) {
var deferred = $q.defer();
if (!lodash.isNil(accountId)) {
try {
deferred.resolve(restangular.one('user')
.one('contactimages')
.get({ 'mappedRelatedContactsPath': $scope.mappedRelatedContactsPath, "account": accountId }));
}
catch (err) {
$scope.contactsPopulated = false;
deferred.reject(err);
}
}
deferred.promise.then(function (response) {
var tests = response;
return $q.when();
},
function () {
console.log("1st reject");
return $q.reject();
});
return deferred.promise;
};

Karma - Spied function error handling

I have a service like this:
app.service('usersService.v2', ['$http', '$q', '$exceptionHandler', 'User', 'userValidator.v2', 'CRUD', function($http, $q, $exceptionHandler, User, userValidator, CRUD){
function dummyPromise(){
var dummyDeferred = $q.defer();
dummyDeferred.resolve('dummy');
return deferred.promise;
}
this.getUser = function(userID, companyID){
try{
userValidator.validateId(userID);
userValidator.validateId(companyID);
}
catch(e){
$exceptionHandler(e);
return dummyPromise();
}
return $http.get(apiUrl + 'api/v2/companies/' + companyID + '/users/' + userID)
.then(function(response){
var user = new User(response.data);
try{
userValidator.validateUser(CRUD.READ, user);
}
catch(e){
$exceptionHandler(e);
return;
}
return user;
})
};
}]);
And basically I want to test the behaviour of this service depending on what the validation functions do.
userValidator.* function are if/else blocks throwing errors.
In Karma I have something like this:
describe('Service: usersService.v2', function () {
var usersService, httpBackend, state, userValidator;
const url = 'address'
function _inject() {
angular.mock.inject(function ($injector) {
usersService = $injector.get('usersService.v2');
userValidator = $injector.get('userValidator.v2');
httpBackend = $injector.get('$httpBackend');
});
}
beforeEach(function () {
angular.mock.module('app');
_inject();
});
describe('getUser', function () {
beforeEach(function () {
httpBackend.when('GET', url);
});
afterEach(function () {
httpBackend.verifyNoOutstandingExpectation();
httpBackend.verifyNoOutstandingRequest();
});
it('should return a dummy promise if ID validation fails', function(){
spyOn(userValidator, 'validateId').and.throwError('Missing or wrong ID thrown');
usersService.getUser()
.then(function(data){expect(data).toBe('dummy');})
});
)};
})
but when I'm running Karma I get an error, as it would be if I didn't put the catch to handle the expection and the following block of code is not executed.
What am I doing wrong?
Cheers,
Manuel
UPDATE:
Validate methods are something like this:
... code code code ...
this.validateId = function(ID){
if(!ID || !angular.isNumber(ID)) throw 'Missing or wrong ID';
}
Thus my problem is that Karma is trying to handle the error thrown by validation instead of let the userService do it.
You are testing usersService.v2.You can not test the userValidator.v2 at the same time.But you can mock the userValidator.v2 service.
var userValidator;
beforeEach(function() {
module(function($provider) {
userValidator = {
validateId: function(id) {
if (id === 123 ||id === 456 ) { //put your mock test id here for PASS case
return true
}
return false;
}
}
$provider.value('userValidator.v2', userValidator);
})
});
describe('getUser', function () {
beforeEach(function () {
httpBackend.when('GET', url)
.respond(200, {
data: "dummy"
});;
});
it('should return a dummy promise if ID validation fails', function() {
usersService.getUser(9879,8798) //Its FAILED case
.then(function(data) { expect(data).toBe('dummy'); })
})
})

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);
});

Share updated variable with factory (variable scope)

I would like to share an updated variable (updated from a function) through a factory (Angularjs)
I have the following factory:
appTspSrv.factory('shared', function(db) {
var entities;
var getEntities = function(){
db.query('getEntities', function(err, doc) {
if (err) {
console.log(err);
} else {
entities = doc.rows;
}
});
};
getEntities();
return {
getEntities: function() {
return entities;
}
}
});
When I call my factory's function from the controller I get 'undifined':
console.log(shared.getEntities());
Why is that and how can I fix this?

Promises in angularjs controller - how to implement

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);
});
};

Categories