I've currently got an endpoint that relies on a JSON body in order for deletion to happen. This is the following code:
if (toDeleteValue.length > 0) {
var deleteRequest = [];
for (var i = 0; i < toDeleteValue.length; i++) {
var service = {};
service.serviceId = $scope.siteServices[toDeleteService[i]].serviceId;
toDeleteValue.push(service);
}
var deleteUrl = "api/class/" + $scope.targetEntity.serviceId+ "/student";
await asyncDeleteUrl(deleteUrl, deleteRequest);
}
async function asyncDeleteUrl(deleteUrl, toBeDeleted) {
return new Promise(function (resolve, reject) {
$http.delete(deleteUrl, toBeDeleted)
.then(function (response) {
resolve(response);
},
function (errorResponse) {
reject(errorResponse);
$scope.statusDialog('Bad Modification Interrupted', errorResponse);
});
});
}
I keep getting an error saying the required rest body is missing but I'm not sure why that would be the case. Any help would be appreciated, thank you.
The second argument of the $http.delete method is a config object. Send data using the data property of that object:
function asyncDeleteUrl(deleteUrl, toBeDeleted) {
var config = { data: toBeDeleted };
return $http.delete(deleteUrl, config)
.catch(function (errorResponse) {
$scope.statusDialog('Bad Modification Interrupted', errorResponse);
throw errorResponse;
});
}
For more information, see
AngularJS $http Service API Reference - delete
Related
Here is my code for factory method using $resource
(function () {
"use strict";
angular.module("common.services")
.factory("lookupResource", ["$resource", "appsettings", lookupResource])
function lookupResource($resource, appsettings) {
return {
lookupUserRoles: $resource(appsettings.serverpath + "api/UserRoles", null,
{
'userRoles': { method: 'get' }
}),
lookupStaffTypes: $resource(appsettings.serverpath + "api/StaffTypes", null,
{
'staffTypes': { method: 'get' }
})
}
}
})();
I am trying to call the lookupStaffTypes using below code but it gives no data or error. What am I missing here?
lookupResource.lookupStaffTypes.staffTypes( function (data) {
var test = data;
},
function (response) {
vm.message = response.statusText + "\r\n"
if (response.data.exceptionMessage)
{ vm.message += response.data.exceptionMessage }
//validation errors
if (response.data.error) {
vm.message += response.data.error;
}
});
Where as I can call like this and it gives me data:
var staffTypes = $http.get(appsettings.serverpath + "api/StaffTypes").then(function (dataResponse) {
var qwe = dataResponse;
for (var i = 0; i < dataResponse.data.length; i++) {
$scope.staffTypeList.push(dataResponse.data[i]);
}
}, function (response) {
vm.message = response.statusText + "\r\n"
if (response.data.exceptionMessage)
{ vm.message += response.data.exceptionMessage }
//validation errors
if (response.data.error) {
vm.message += response.data.error;
}
});
I am new to angular and any help would be highly appreciated!
I recommend avoiding the ngResource module and just using the $http service directly. If a server implements a RESTful API, I recommend using Restangular.
That said, for ngResource:
If the server returns an array, it is important to define the action method with isArray: true:
app.factory("lookupResource", ["$resource", "appsettings", lookupResource])
function lookupResource($resource, appsettings) {
return {
lookupStaffTypes: $resource(appsettings.serverpath + "api/StaffTypes", null,
{
'staffTypes': { method: 'get',
isArray: true }
})
}
}
Invoke it with:
$scope.staffTypeList = lookupResource.lookupStaffTypes.staffTypes();
//OR
$scope.staffTypeList = lookupResource.lookupStaffTypes.query();
It is important to realize that invoking a $resource object method immediately returns an empty reference (object or array depending on isArray). Once the data is returned from the server the existing reference is populated with the actual data.
If the service expects an object but receives an array, or vice versa, it will generate a $resource:badcfg error. If the service returns a boolean or a string, the action method will quietly return nothing.
Use the $promise propery of the received object (or array) to chain sequential operations:
$scope.staffTypeList.$promise.then(function(staffTypeList) {
console.log(staffTypeList);
//Do more stuff
});
I am trying to invoke a Java REST API from Angular JS using Restangular. I am able to see proper response in the network tab but the response object is having empty array while i try to log the same in console or display in the html file.
class TestClass {
/*#ngInject*/
constructor($log, Restangular) {
this.Restangular = Restangular;
this.$log = $log;
this.test = "somethings";
var me = this;
this.Restangular.all('api/people/').getList().then(response => {
this.test = response;
console.log(response);
});
}
I have the following configurations defined in my app.js file
.config(/*#ngInject*/function(RestangularProvider) {
RestangularProvider.setBaseUrl('http://localhost:8080/');
RestangularProvider.setFullResponse(true);
RestangularProvider.addResponseInterceptor(function(data, operation, what, url, response, deferred) {
var extractedData;
if (operation === "getList") {
extractedData = data.result;
} else {
extractedData = data;
}
return extractedData;
});
})
Console
Network
You should be sure the response from Restangular getList() is in data.result and not in some other data property...
I'm trying to create an AngularJS service, which returns data based on several HTTP requests. But i seem to just not get it to work.
The REST call works as follow:
get /index which returns an array of urls
call each of the url's, and add the result to an array
I expect that at the end of the call of the service function, that i receive a data structure containing all the data from the url's.
My current, somewhat working code uses callbacks, but even though it works in one controller, it does not in another. I want to correctly use promises, but i'm already confused with success vs then.
My service:
// Get a image
obj.getByUrl = function (imageUrl, callback) {
$http.get('https://localhost:9000' + imageUrl).success(function (data) {
callback(data);
});
}
// Get all images
obj.getAll = function(callback) {
$http.get('https://localhost:9000/1.0/images').success(function (data) {
if (data.status != "Success") {
console.log("Err");
}
var images = [];
for(var n=0; n < data.metadata.length; n++) {
var c = data.metadata[n];
obj.getByUrl(c, function(data2) {
images.push(data2.metadata);
});
}
callback(images);
});
}
i'd like to use the service in a controller resolve like this:
resolve : {
images: function(ImagesServices, $route) {
return ImagesServices.getState($route.current.params.containerName)
},
I came as far as this, but it does only return the data of the index call, not the aggregated data:
obj.getAll3 = function() {
var images = [];
var promises = [];
//var httpPromise = $http.get('https://localhost:9000/1.0/images');
var httpPromise = $http({
url: 'https://localhost:9000/1.0/images',
method: 'GET',
});
return httpPromise.success(function(data) {
var data2 = data.metadata[0];
// angular.forEach(data.metadata, function(data2) {
console.log("D11: " + JSON.stringify(data2));
//var inPromise = $http.get('https://localhost:9000' + data2)
var inPromise = $http({
url: 'https://localhost:9000' + data2,
method: 'GET',
})
.success(function (data2) {
console.log("D2: " + JSON.stringify(data2));
images.push(data2);
});
promises.push(inPromise);
// });
return $q.all(promises).then(function() {
return images;
});
});
}
Maybe someone can point me into the right direction?
This is the typical case where chaining promises, and using $q.all(), is adequate:
/**
* returns a promise of array of images
*/
obj.getAll = function() {
// start by executing the first request
return $http.get('https://localhost:9000/1.0/images').then(function(response) {
// transform the response into a promise of images
// if that's not possible, return a rejected promise
if (data.status != "Success") {
return $q.reject("Error");
}
// otherwise, transform the metadata array into
// an array of promises of image
var promises = data.metadata.map(function(imageUrl) {
return $http.get('https://localhost:9000' + imageUrl).then(function(resp) {
return resp.data;
});
});
// and transform this array of promises into a promise
// of array of images
return $q.all(promises);
});
}
This avoid the callback antipattern, and uses chaining. It's a bit long to explain here, but I wrote a blog post that should, hopefully, make the above code clear: http://blog.ninja-squad.com/2015/05/28/angularjs-promises/
Overview:
I'm creating an app using ionic framework and AngularJS. The App has 2 forms where user can upload images. In first form, image upload field allows to upload only one image and second form image upload field allows to upload more than one images. After user uploads images I'm showing preview to user right below image field. Then user click on "Save", which calls Web Service (defined into factory) to upload images to site. The Service function implements $q, so that form submission can continue only after uploading images. This is working fine.
Problem:
When uploading multiple images, I'm calling another helper function in controller which loop (forEach) over file data and call file save function for each file. But the execution in this helper function doesn't wait for forEach loop to complete. This is allowing me to get first file details of file saved, but not remaining saved files details.
Here is code I'm using for uploading file:
.controller('AppCtrl', function($q) {
// Upload single file.
$scope.fileUpload = function(fileData) {
var deferred = $q.defer();
if (angular.isUndefined(fileData) || angular.isUndefined(fileData.dataURL)) {
deferred.resolve("No new upload found.");
}
else {
var filedata = {
"file" : {
file: (fileData.dataURL).replace(/^data:image\/[A-Za-z]{3,4};base64,+/g, ''),
filename: fileData.file.name,
},
};
AuthServiceContent.uploadNewFile(filedata).then(function(response) {
deferred.resolve(response);
}, function(response) {
deferred.reject(response);
});
}
return deferred.promise;
};
// Upload multiple files.
$scope.fileUploadMultiple = function(data) {
var deferred = $q.defer();
var fileUploadStatus = [];
if (angular.isUndefined(data) || angular.isUndefined(data[0])) {
deferred.reject("No new upload found.");
}
else {
angular.forEach(data, function(fileData, index) {
$scope.fileUpload(fileData).then(function(response) {
fileUploadStatus[index] = response;
}, function(response) {
});
});
}
return (!angular.isUndefined(fileUploadStatus) ? deferred.resolve(fileUploadStatus) : deferred.reject(fileUploadStatus));
};
$scope.createContent = function(formData) {
$scope.fileUploadMultiple(formData.image).then(function(response) {
if (angular.isObject(response)) {
angular.forEach(response, function(fileData, index) {
console.log(fileData);
formData.image.und = [{'fid' : fileData.fid}];
});
console.log(formData);
}
else {
}
}, function(err) {
console.log("updates failed!!!");
});
return;
};
})
.factory('AuthServiceContent', function($q, $http, DEFAULT) {
var service_content = {
uploadNewFile: function(fileData) {
var deferred = $q.defer();
$http.post(DEFAULT.serviceURL + 'file', JSON.stringify(fileData), {
headers : {
'Content-Type': 'application/json',
'Cookie': 'cookieData',
}
})
.success(function (data, status, headers, config) {
deferred.resolve(data);
})
.error(function (data, status, headers, config) {
deferred.reject(data);
});
return deferred.promise;
}
};
return service_content;
});
I've been trying this for more than 2 days and find similar issue, but its not working.
Updates:
I got this working by adding extra check in loop, here is updated function in controller to upload multiple images.
$scope.fileUploadMultiple = function(data) {
var deferred = $q.defer();
var fileUploadStatus = [];
if (angular.isUndefined(data) || angular.isUndefined(data[0])) {
deferred.reject("No new upload found.");
}
else {
var dataLength = (data.length - 1);
angular.forEach(data, function(fileData, index) {
$scope.fileUpload(fileData).then(function(response) {
fileUploadStatus[index] = response;
// Check if we are at last element. If yes, then return status
// Return deffered status on last element.
if (dataLength == index) {
deferred.resolve(fileUploadStatus);
}
}, function(response) {
// Check if we are at last element. If yes, then return status
// Return deffered status on last element.
if (dataLength == index) {
deferred.reject(fileUploadStatus);
}
});
});
}
return deferred.promise;
};
The problem is that you have only one promise and are resolving it as soon as the first call uploaded file returns its results.
Save all the promises in an array and then try $q.all:
var promises = [];
angular.forEach(data, function(fileData, index) {
promises.push($scope.fileUpload(fileData));
});
$q.all(promises).then(function(results) {
// loop through the results, one for each promise, and do what you need
})
or just return $q.all(promises) and let the application code handle the results.
The big problem with $q.all is that it just gives and error if ANY of the promises is rejected. If you still want to handle the results for each promise, I use an implementation of $q.allSettled (I think I use this implementation. That returns a response for each promise -- either success or failure -- with the error message or the returned data so that I can then handle the results of each promise separately.
Hope this helps
The updated code in the answer is not working. If the last file is the smallest, it fires the resolve immediately after it's been uploaded. I use instead a fileIsUplaoded counter.
$scope.fileUploadMultiple = function(data) {
var deferred = $q.defer();
var fileUploadStatus = [];
if (angular.isUndefined(data) || angular.isUndefined(data[0])) {
deferred.reject("No new upload found.");
}
else {
var uploadCount = data.length;
angular.forEach(data, function(fileData, index) {
$scope.fileUpload(fileData).then(function(response) {
// if a file is uploaded reduce the uploadCount by 1
uploadCount --;
fileUploadStatus[index] = response;
// Check if we are at last element. If yes, then return status
// Return deffered status on last element.
if (uploadCount == 0) {
deferred.resolve(fileUploadStatus);
}
}, function(response) {
// if a file is not uploaded reduce the uploadCount by 1
uploadCount --;
// Check if we are at last element. If yes, then return status
// Return deffered status on last element.
if (uploadCount == 0) {
deferred.reject(fileUploadStatus);
}
});
});
}
return deferred.promise;
};
So I have a simple example of using $q.all to batch $resource calls, what I want to know is why is my update handler never called?
I would have thought it would be called after each promise is successfully completed?
Only the result handler is called. What am I doing wrong?
Here is the code snippet:
var promises = [];
angular.forEach($scope.mappedData, function(item) {
var resource = new Resource(item);
promises.push(resource.$save());
});
$q.all(promises).then(
function(result) {
console.log('result', result);
},
function(error) {
console.log('error', error);
},
function(notify) {
console.log('notify', notify);
}
);
$q.all creates a new singular promise that once all the previous promises are complete will then continue on. If you want to do each one individually you'll have to reference them individually.
I had the same problem, and I came with this solution. I've tried to arrange the code for your case.
var results = [], errors = [], d = $q.defer()
angular.forEach($scope.mappedData, function(item) {
var resource = new Resource(item);
resource.$save().promise
.then(function (result) {
results.push(result)
if(results.length == $scope.mappedData.length)
d.resolve(results)
}, function (err) {
errors.push(err)
results.push(null) // Very important =P
}, function (notf) {
d.notify(notf)
})
})
d.promise.then(function (results) {
console.log(results)
}, function (err) {
console.error(err)
}, function (notf) {
console.info(notf)
})
Let me know if it helps ;)