AngularJS Request payload is always empty - angularjs

I have created a Angular resource that sends POST data to a web service. Here is my factory:
appServices.factory('Foo', function($resource) {
var data = $resource(
'http://localhost:3000/api/v1/foo.json',
{},
{
'save': {
method: 'POST',
cache: false
}
});
return data;
});
Here's my Controller:
appControllers.controller('FooCtrl', function($scope, Foo, $location) {
$scope.memberData = {};
$scope.create = function() {
var member = new Foo();
member.$save( {}, { bar: bar });
$location.url("/");
};
});
When I submit the form in my client, it returns a 500 status. Looking into Firebug, I can see that my POST data payload always remains empty for some reason.
What am I doing wrong?
PS. I've added this to my config: $httpProvider.defaults.headers.post['Content-Type'] = 'application/json; charset=utf-8';

If you want to issue a POST request to the member resource, you can use save() (without the $) and pass in your body as the first argument:
Foo.save({bar: 'bar'}, function () {
// Callback
});
However, when creating a new resource instance, it is augmented with a $save() method (note the $). When you invoke this method, the instance itself is sent as the body. So you should change your code to:
var member = new Foo();
member['bar'] = 'bar';
member.$save(function () {
// Callback
});
Check this article for more information.

Related

AngularJS : Render controller without waiting factory variable to be intialized first

First, I'm new to angularjs. I've create a factory to handle most of my data named "store". Here is an example:
app.factory('store', function ($rootScope, $http, $q, api) {
var data = {};
return {
setData: function () {
var deferred = $q.defer();
$http({
method: 'GET',
url: api.getData()
}).then(function successCallback(response) {
// handle data
$rootScope.broadcast('store:data', data);
deferred.resolve();
}, function errorCallback(reponse) {
// do stuff
deferred.reject();
});
},
getData: function () {
return data;
},
addData: function (newData) {
// do stuff
},
editData: function (newData) {
// do stuff
},
deleteData: function (newData) {
// do stuff
}
};
});
I'm initializing this data inside my app.run function. BUT, I don't want my app to wait my data to be initialized first to render the controller. I want it to be rendered first and wait for updating when the data is initialized.
store.setData()
.then(function (response) {
// do stuff
})
.catch(function (response) {
// do stuff
});
Here is how I'm getting the data updated inside my controller to be rendered
$scope.data = store.getData();
$rootScope.$on('store:data', function (event, data) {
$scope.data = data;
})
SO my problem is that I don't want to wait my data to be initialized to render my controller.
Is there a solution to this problem ?
Thanks a lot.
EDIT May 20 2021
Btw if what I'm doing is wrong and there is better things to do, I'm open to any suggestions ! Thnx
EDIT June 9 2021
Now I'm using $resource, but I don't know how can I get the new version of my list of data when I add new element to it.
agents: $resource(
api.getAgents(),
{},
{
get: {method: 'GET', isArray: false, cache: true},
add: {method: 'POST', url: api.addAgent(), hasBody: true},
edit: {method: 'PUT', url: api.editAgent(), params: {agentId: '#id'}, hasBody: true},
delete: {method: 'DELETE', url: api.deleteAgent(), params: {agentId: '#id'}},
}
),
Waiting for an answer. Thank you vm !
There are a couple options you can consider, but first a note on best practices in AngularJS and JavaScript: avoid the deferred antipattern. The $http service returns a promise. You should work with that rather than creating a new promise with $q.defer.
The first option is to change the getData method to return a promise instead of the actual data. It is a good idea to always design your data retrieval services to return promises, even when you intend to pre-retrieve and cache the data. This provides the cleanest way to ensure that the data is available before you try to use it. In your example, you should be able to internally cache the promise rather than the data. So your code would change to something like this:
app.factory('store', function ($rootScope, $http, api) {
var dataPromise;
return {
setData: function () {
dataPromise = $http({
method: 'GET',
url: api.getData()
}).then(function successCallback(response) {
// handle data
$rootScope.broadcast('store:data', data);
}, function errorCallback(reponse) {
// do stuff
});
},
getData: function () {
if (!dataPromise) {
this.setData();
}
return dataPromise;
},
// etc.
};
}
You will of course have to change the code that calls the getData method to work with the promise instead of working directly with the data.
Another option is to use an AngularJS Resource. This feature works very much like your original intent by returning an instance of an object that at some point will get populated with data. It takes advantage of the AngularJS change detection to render the data once it becomes available. Resources also have the ability to cache responses internally so that the call to the server is only made once. Rewriting your service as a resource would look something like this:
app.factory('store', function ($rootScope, $resource, api) {
return $resource(
api.getData(), // the base URL
{}, // parameter defaults
{ // actions
getData: {
method: 'GET',
cache: true
},
// etc.
}
);
}

Data bind works only on second click event

I have a click event to call the AngularJS function which retrieves the data from SQL and return to the ajax call.
My problem is the data which is retrieved binds with ng-repeat only on the second click event.Here is my code,
`
(function (app) {
app.controller("OnvioController", function ($scope,$http, OnvioService) {
$scope.retData = [];
$scope.getResult = function () {
var serviceURL =window.location.origin+ '/Datafetching/dataFetch';
$.ajax({
type: "POST",
url: serviceURL,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(data, status) {
$scope.retData = data;
},
error: function (status) {
}
});
}
});
}(angular.module("OnvioModule")));
`
Do not use $.ajax in angularJS.
You can do this by $http.get
I haven't tried it my self right now. but it should work in your case.
(function (app) {
app.controller("OnvioController", function ($scope,$http, OnvioService) {
$scope.retData = [];
$scope.getResult = function () {
var serviceURL =window.location.origin+ '/Datafetching/dataFetch';
$http.get(serviceURL).success( function(response) {
$scope.retData = response;
});
}
});
}(angular.module("OnvioModule")));
refer this document for more details
Use $http.post instead of $.ajax.
If you still want to use $.ajax add a $scope.$apply() in your success function.
This will trigger angular loop to search for changes outside of his context. This is because $.ajax is executing outside of angular stuff.
Add a $scope.$apply() in your success function.

How to return server response via $service.save()

I am new in AngularJS and I have got this problem. I have got defined service citiesService with method addCity:
.service('citiesService', ['$resource', function($resource){
this.addCity = function(city) {
var cityItem = $resource("server/?module=cities&action=add", {}, {save: {method: "POST", isArray:true}});
return cityItem.save({
city: city
});
};
}])
It works fine, the new city was successfully added into DB via the PHP script, but I don't know, how to return server response. Server returning response like:
$output = [];
$output[] = ["success" => "added to database"];
echo json_encode($output);
and then I have got this controller:
.controller('citiesAddCtrl', function($scope, $modalInstance, citiesService) {
// save addCity form (modal)
$scope.saveForm = function() {
if($scope.city.name) {
$scope.a = citiesService.addCity($scope.city);
}
}
})
but I really don't know, how to display server JSON response. When I try something like console.log($scope.a), It shown empty array, but as you can see, the server response is in the right debug menu:
Can you help me to solve this problem please? I read some Stackoverflow topics and tried some edits, which are described here, but nothing works for me.
Since save returns a promise, you could access the response as following (untested):
.controller('citiesAddCtrl', function($scope, $modalInstance, citiesService) {
// save addCity form (modal)
$scope.saveForm = function() {
if($scope.city.name) {
citiesService.addCity($scope.city).$promise.then(function(response) {
$scope.a = response
});
}
}
})
Why don't you use simply $http which has a clear promise structure?
$http({
method: 'POST',
url: "server/?module=cities&action=add",
data: $scope.city
}).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
See docs at $http

POST to nested RESTful resources with $resource parameter mismatch - AngularJS

I'm trying to using the $resource library of angular, to POST data to a nested resource.
My following nested resource of event looks like so
events/:eventId/match - POST
events/:eventId/match - GET
events/:eventId/match/:matchId - GET
I set up a service with angular
app.factory('EventService', ['$resource', function ($resource) {
var Event = $resource('/events/:eventId', {eventId: '#id'},
{
createMatches: {
url: '/events/:eventId/match',
method: 'POST'
}
);
return {
createMatches: function(data,event_id) {
var data.eventId = event_id;
return Event.createMatches(data).$promise;
}
}
});
Controller where it has been called:
app.controller('EventController', ['$scope','EventService', function($scope,EventService) {
$scope.create = function(event_id,title,description) {
EventService.createMatches({
title:title,
description: description
},event_id).then(function(result) {
console.log('event_created', result);
})
}
}]);
Problem
When I send the request to the server I expect the url that looks like so: /events/10/match
But instead the resource doesn't add the eventId as a parameter of the url but add it as a parameter of the request, for this reason my call fail because the url looks like so: /events/match.
I can't understand why it doesn't bind the :eventId to the url. Any suggest will be appreciated.
I believe that you are missing your second parameter decalaration, as per this link for the actions you are defining:
app.factory('EventService', ['$resource', function ($resource) {
var Event = $resource('/events/:eventId', {eventId: '#id'},
{
createMatches: {
url: '/events/:eventId/match',
method: 'POST',
params: {eventId: '#id'}
}
);
return {
createMatches: function(data,event_id) {
var data.eventId = event_id;
return Event.createMatches(data).$promise;
}
}
});

AngularJS - scope variable does not get updated from method

I'm totally new to AngularJs and I have this problem I do not understand. I have two methods. The first one takes some data from a webservice and puts in in a variable defined in the scope. But when I want to use that variable in the second method it is undefined. Can someone help me understand why this is happening and provide a solution?
var myApp= angular.module( "myApp", [] );
myApp.controller("myAppController",
function( $scope ) {
$scope.getAll = function(){
$.ajax({
type: "GET",
dataType: "jsonp",
contentType: "application/json; charset=utf-8",
url: ..something...,
success: function (parameters) {
$scope.profiles = angular.copy(parameters); <-- correct data is returned
$scope.$apply();
},
error: function () {
alert("Error calling the web service.");
}
});
}
$scope.getCategories = function(){
var all = $scope.profiles; <-- At this point profiles is empty
...
}
$scope.getAll();
$scope.getCategories();
}
Use the $http service and promises:
$scope.profiles = $http.jsonp(url).then(function(r){ return r.data; });
$scope.categories = $scope.profiles.then(function(profiles) {
var params = { }; // build url params
return $http.jsonp(url, { params: params }).then(function(r){ return r.data; });
});
When you call getCategories(), getAll() hasn't finished yet, which is why profiles is empty. There are several ways to solve this. The best way would be to use promises the built-in $http service.
If you prefer to use jQuery, you can add a watcher on the profiles variable and only when it's populated run the getCategories().
Something like this should work:
$scope.getAll = function(){
$.ajax({
type: "GET",
dataType: "jsonp",
contentType: "application/json; charset=utf-8",
url: ..something...,
success: function (parameters) {
$scope.profiles = angular.copy(parameters); <-- correct data is returned
$scope.$apply();
},
error: function () {
alert("Error calling the web service.");
}
});
}
$scope.getCategories = function(){
var all = $scope.profiles;
}
// Wait for the profiles to be loaded
$scope.watch('profiles', function() {
$scope.getCategories();
}
$scope.getAll();
There is no guarantee that getAll has completed before getCategories is invoked, since it is an asynchronous request. So if you want to sequentially invoke getAll and getCategories, you should invoke getCategories inside the success callback of getAll. You could also look into promises for a neater way of chaining asynchronous callbacks (I assume you're using jQuery since you're calling $.ajax).
...
<snipped some code>
success: function(parameters) {
// snipped more code
$scope.getCategories();
}
(and if you're using jQuery promises)
$.ajax(ajaxCallOneOpts).then($.ajax(ajaxCallTwoOpts));
Neither are very "Angularish" though, so you might want to look into some of the provided services for working with http/rest resources instead of using jQuery.
Why are you using a jQuery ajax request in angular? If you write jQuery style code and wrap it angular, you're going to have a bad time...
Here is an angularised version:
myApp.controller("myAppController",
function( $scope, $q, $http ) {
$scope.getAll = function(){
var deferred = $q.defer();
$scope.profiles = deferred.promise;
$http.jsonp('your url').then(function(data) {
deferred.resolve(data);
});
});
$scope.getCategories = function(){
$q.when($scope.profiles).then(function(profiles) {
... <-- At this point profiles is populated
});
}
$scope.getAll();
$scope.getCategories();
}

Resources