AngularJS: Error 204 (no content) - angularjs

I have this Angular Controller:
(function () {
"use strict";
angular.module('appContacts')
.controller('organizationsController', function organizationsController(dataService, $stateParams) {
var vm = this;
vm.visible = false;
var id = $stateParams.Id;
activate();
function activate() {
dataService.GetOrganizationById(id).then(function (result) {
vm.organization = result.data;
}, function () {
vm.errorMessage = "Failed to load" + Error;
});
}
});
})();
Here is my dataService file:
(function () {
angular.module('appContacts')
.factory('dataService', ['$http', dataService]);
function dataService($http) {
return {
getAllOrganizations: getAllOrganizations,
GetOrganizationById: GetOrganizationById,
};
function getAllOrganizations() {
return $http({
method: 'GET',
url: 'api/organizations'
});
}
function GetOrganizationById(id) {
return $http({
method: 'GET',
url: '/api/organizations/{id}'
});
}
})();
This dataService.js call the GetOrganizationById method in the repository like this:
...
public Organization GetOrganizationById(Guid Id)
{
return _context.Organizations
.Include(o => o.Contacts)
.ThenInclude(c => c.Phone.main == true)
.Where(o => o.Id == Id)
.FirstOrDefault();
}
...
The repository gets the info successfully, send back to dataService.js and reach this line in the organizationsController.js. I could see in the Chrome debugger:
dataService.GetOrganizationById(id).then(function (result)
However in the next line, the data is lost and the system returns a 204 Error Code: No Data.
vm.organization = result.data;
Any idea why the Controller would not accept the data that is sent in the variable "result"?
I am working in Visual Studio 2015 EF and C# the back end. But the problem is just in the front-end because I get info and I see it also with Postman

Related

Ionic angular service only return data after controller call

I have a service that do two $http.get to get data from two source and concat into an array and return it to controller.
angular.module('starter.controllers').factory('GetDataList', function ($http) {
var arrDataList = [];
var postData1 = {
"param": "1"
};
var postData2 = {
"param": "2"
};
$http({
method: 'GET',
url: 'https://localhost/search',
data: postData1
})
.then(function (items) {
debugger
arrDataList = arrDataList.concat(items.data.list);
});
$http({
method: 'GET',
url: 'https://localhost/locate',
data: postData2
})
.then(function (items) {
debugger
arrDataList = arrDataList.concat(items.data.list);
});
return {
getAPIData: function () {
debugger
return arrDataList;
}
};
});
In my controller, I call it like this:
$scope.GetList = function () {
debugger
$scope.item = GetDataList.getAPIData();
$scope.$broadcast('scroll.infiniteScrollComplete');
}
When I use the debugger in console, I notice that
1) getAPIData() will be called first but it has data in it
2) Next debugger triggered at the controller which GetDataList.getAPIData(); does not return any data for $scope.Item
3) The last debugger reach $http call which return the data correctly as I observed in the console. But it never reach the controller side afterwards so no data is being displayed in the mobile app
I read about the natural behavior of angular async call so this seems to be normal. But in my case, what should I do to ensure that the data could reach the controller?
Many thanks
To achieve that without loosing performance, you should use $q.all(), so it will keep your request async and it will return the data once all the promises are resolved. Don't try a synchronic approach because that will reduce your performance.
You can use it like this:
Your factory:
app.factory('GetDataList', function($q, $http) {
var promises = [];
var arrDataList = [];
var requests = [{
url: 'https://localhost/search',
postData: {
"param": "1"
}
}, {
url: 'https://localhost/locate',
postData: {
"param": "2"
}
}];
angular.forEach(requests, function(req) {
executeRequest(req);
})
function resolveData(data) {
debugger
if (arrDataList.length === 0) {
arrDataList = data.data;
} else {
arrDataList = arrDataList.concat(data.data);
}
}
function executeRequest(req) {
var promise = $http({
url: req.url,
method: 'GET',
data: req.postData
})
.then(resolveData);
promises.push(promise)
}
return {
getAPIData: function() {
debugger
return $q.all(promises).then(function() {
return arrDataList
});
}
}
});
And your controller:
$scope.GetList = function() {
debugger
GetDataList.getAPIData().then(function(item) {
$scope.item = item
});
$scope.$broadcast('scroll.infiniteScrollComplete');
}
What we are doing here is executing each request inside the requests array (using its url and postData) asynchronously and saving the promises inside an array. When getApiData is called, it returns a function that will be called after $q.all(promises), that means it will return the data after all those promises are finished (the promises ask if the arrDataList is empty and concats the new data if it's not).
This way you get to keep your async calls! And inside the controller you receive a promise instead of the data itself.
You should make it to be synchronized as in the below
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope,serviceDemo) {
$scope.name = 'World';
});
app.factory('serviceDemo', function ($http) {
var arrDataList = [];
var postData1 = []; var postData2 =[]
var firstMethod=function(){
$http({
method: 'GET',
url: 'a.json'
})
.then(function (response) {
console.log(response);
postData1=response.data;
arrDataList.push(postData1);
// console.log(postData1);
secondMethod(); //put the second method call here
});
}
var secondMethod=function(){
$http({
method: 'GET',
url: 'b.json'
})
.then(function (response) {
postData2=response.data;
arrDataList.push(postData2);
console.log(arrDataList);
});
}
var getAPIData= function () {
firstMethod();
return arrDataList;
}
return {
getAPIData: getAPIData
};
});
Modification Made:
You need to call the second method inside the success block of your first method. By this way your first method gets executed, when the result is fetched your second method gets executed and then only control will come out of the first method block.
LIVE DEMO

Ionic. Using $http giving error Cannot read property 'protocol' of undefined

This question is related to another one.
Before I did added $ionicPlatform, my service working just fine, but now there is something wrong with $http.
Here is example of injectables:
(function () {
"use strict";
angular.module('service', ['ionic'])
.service('BBNService', ["$http", "$localStorage", "$ionicPlatform",
function ($http, $localStorage, $ionicPlatform) {
And using of $http and $ionicPlatform
this.tips = function () {
var url;
$ionicPlatform.ready(function () {
if (window.Connection) {
if (navigator.connection.type == Connection.CELL_4G || navigator.connection.type == Connection.WIFI) {
if (this.getDayId = 0)//If Sunday - retrieve updated tips
url = this.host + "/tips/";
else
url = "data/tips.json";//If not - use saved data
}
}
});
var request = $http({
method: "GET",
url: url
}).then(
function mySucces(response) {
return response.data;
},
function myError(response) {
return response.data;
});
return request;
};
You need to send back the promise, doing a return response.data is not gonna work.
var deferred = $q.defer();
var request = $http({
method: "GET",
url: url
}).then(
function mySucces(response) {
deferred.resolve(response.data);
},
function myError(response) {
deferred.reject(response.data);
});
return deferred.promise;
And at the place where you consume this service:
BBNService.tips().then(
function(data) { //success call back with data },
function(data) { //error call back with data }
);
Please let me know if you need more explanation on using $q; always happy to give more details.

How to set a variable from an $http call then use it in the rest of the application WITHOUT making the whole application asynchronous

I have this data
{
"config": {
"RESTAPIURL": "http://myserver/myrestsite"
}
}
and I have this factory that reads that data
'use strict';
angular.module('myApp').factory('api',
["$http", "$q",
function ($http, $q) {
function _getConfiguration() {
var deferred = $q.defer();
$http.get('/scripts/constants/config.json')
.success(function (data) {
deferred.resolve(data);
})
.error(function (data, status) {
deferred.reject(data, status);
});
return deferred.promise;
}
function _restApiUrl() {
// this doesn't work either. _getConfiguration() doesn't resolve here.
return _getConfiguration().RESTAPIURL + '/api/';
}
return {
URL: _restApiUrl
}
}
]
);
Then to use it
'use strict';
angular.module('myApp').factory('AuthService', function ($http, $q, api,NotificationService) {
function _get(creds) {
var deferred = $q.defer();
$http({method: 'GET', url: api.URL() + api.AUTH, headers: {
'Authorization': 'Basic '+creds}
})
.success(function (data, status, results, headers) {
deferred.resolve(results);
})
.error(function (data, status) {
NotificationService.redirect(status);
deferred.reject(data, status);
});
return deferred.promise;
}
return {
get:_get
};
});
So when I'm using it I am doing api.URL() and it's not working.
It used to be hard coded URL so to call it used to be api.URL. I really don't want to go through the whole app and convert everything to api.URL().then(...). That would suck.
So how can I nail down this value as a "property" instead of an asynchronous promise that has to be called over and over?
Call it once, fine. Get the value. Put it somewhere. Use the value. Don't ever call the $http again after that.
EDIT
This is turning up to be one of the most successful questions I've ever asked, and I am gratefully going through each answer in turn. Thank each one of you.
Adding a bit to what #ThinkingMedia was saying in the comment, with ui-router when defining controllers you can add a resolve parameter.
In it you can specify some promises that have to resolve before the controller is instantiated, thus you are always sure that the config object is available to the controller or other services that the controller is using.
You can also have parent/child controllers in ui-router so you could have a RootController that resolves the config object and all other controllers inheriting from RootController
.state('root', {
abstract: true,
template: '<ui-view></ui-view>',
controller: 'RootController',
resolve:{
config: ['api', function(api){
return api.initialize();
}
}
});
and your api factory:
angular.module('myApp').factory('api',
["$http", "$q",
function ($http, $q) {
var _configObject = null;
function initialize() {
return $http.get('/scripts/constants/config.json')
.then(function (data) {
_configObject = data;
return data;
});
}
// you can call this in other services to get the config object. No need to initialize again
function getConfig() {
return _configObject;
}
return {
initialize: initialize,
getConfig: getConfig
}
}
]
);
I would pass a callback to the getURL method, and save the URL when it returns. Then I would attach any subsequent requests to that callback. Here I am assuming that you are doing something similar with api.AUTH that you don't have a reference to in your code.
Pass a callback to the getURL method in the api service.
angular.module('myApp').factory('api', ["$http", "$q",
function ($http, $q) {
function _getConfiguration() {
var deferred = $q.defer();
$http.get('/scripts/constants/config.json')
.success(function (data) {
deferred.resolve(data);
})
.error(function (data, status) {
deferred.reject(data, status);
});
return deferred.promise;
}
return {
getURL: function (cb) {
var that = this;
if (that.URL) {
return cb(that.URL);
}
_.getConfiguration().then(function (data) {
that.URL = data.config.RESTAPIURL + "/api";
cb(that.URL);
});
}
}
}]);
And in your AuthService, wrap your _get inside a callback like this:
angular.module('myApp').factory('AuthService', function ($http, $q, api, NotificationService) {
function _get(creds) {
var deferred = $q.defer();
var getCallback = function (url) {
$http({
method: 'GET',
url: url + api.AUTH,
headers: {
'Authorization': 'Basic ' + creds
}
})
.success(function (data, status, results, headers) {
deferred.resolve(results);
})
.error(function (data, status) {
NotificationService.redirect(status);
deferred.reject(data, status);
});
};
api.getURL(getCallback);
return deferred.promise;
}
return {
get: _get
};
});
Why don't you initialize the factory when the app is loading and put the variable onto another property? Something like this:
angular.module('myApp').factory('api', ["$http", "$q",
function ($http, $q) {
// store URL in a variable within the factory
var _URL;
function _initFactory() {
var deferred = $q.defer();
$http.get('/scripts/constants/config.json')
.success(function (data) {
// Set your variable after the data is received
_URL = data.RESTAPIURL;
deferred.resolve(data);
});
return deferred.promise;
}
function getURL() {
return _URL;
}
return {
initFactory: _initFactory,
URL: getURL
}
}
]
);
// While the app is initializing a main controller, or w/e you may do, run initFactory
//...
api.initFactory().then(
// may not need to do this if the URL isn't used during other initialization
)
//...
// then to use the variable later
function _get(creds) {
var deferred = $q.defer();
$http({method: 'GET', url: api.URL + api.AUTH, headers: {
'Authorization': 'Basic '+creds}
})
.success(function (data, status, results, headers) {
deferred.resolve(results);
})
return deferred.promise;
}
I see you haven't used any $resource's here, but I'm hoping you have a good understanding of them:
in factories/delay-resource.js:
'use strict'
angular.module('myApp').factory('delayResource', ['$resource', '$q',
function($resource, $q){
var _methods = ['query', 'get', 'delete', 'remove', 'save'];
var shallowClearAndCopy = function(src, dst) {
dst = dst || {};
angular.forEach(dst, function(value, key){
delete dst[key];
});
for (var key in src) {
if (src.hasOwnProperty(key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
dst[key] = src[key];
}
}
return dst;
}
var delayResourceFactory = function(baseUrlPromise, url, paramDefaults){
var _baseUrlPromise = baseUrlPromise,
_url = url,
_paramDefaults = paramDefaults;
var DelayResource = function(value){
shallowClearAndCopy(value || {}, this);
};
_methods.forEach(function(method){
DelayResource[method] = function(params, successCB, errCB, progressCB){
if (angular.isFunction(params)) {
progressCB = successCB;
errCB = errHandlers;
successCB = params;
errHandlers = params = null;
}
else if (!params || angular.isFunction(params)){
progressCB = errCB;
errCB = successCB;
successCB = errHandlers;
params = {};
}
var _makeResultResource = function(url){
var promise = $resource(url, _paramDefaults)[method](params);
(promise.$promise || promise).then(
function successHandler(){
var data = arguments[0];
if (isInstance){
if (angular.isArray(data))
for (var i = 0; i < data.length; i++)
data[i] = new DelayResource(data[i])
else if (angular.isObject(data))
data = new DelayResource(data)
}
successCB.apply(successCB, arguments)
resultDelay.resolve.apply(resultDelay.resolve, arguments)
},
function(err){
errCB.apply(errCB, arguments)
resultDelay.reject.apply(resultDelay.reject, args)
},
function(){
progressCB.apply(progressCB, arguments)
resultDelay.notify.apply(resultDelay.notify, arguments)
}
)
}
var isInstance = this instanceof DelayResource,
resultDelay = $q.defer();
if (!angular.isString(_baseUrlPromise) && angular.isFunction(_baseUrlPromise.then))
_baseUrlPromise.then(
function successCb(apiObj){
_makeResultResource(apiObj.RESTAPIURL + _url)
},
function successCb(){
throw 'ERROR - ' + JSON.stringify(arguments, null, 4)
})
else
_makeResultResource(_baseUrlPromise.RESTAPIURL + _url);
return resultDelay.promise;
};
DelayResource.prototype['$' + method] = function(){
var value = DelayResource[method].apply(DelayResource[method], arguments);
return value.$promise || value;
}
});
return DelayResource;
}
return delayResourceFactory;
}]);
This will be the base factory that all requests to that REST API server will go through.
Then we need a factories/api-resource.js:
angular.module('myApp').factory('apiResource', ['delayResource', 'api', function (delayResource, api) {
return function (url, params) {
return delayResource(api.URL(), url, params);
};
}])
Now all factories created will just have to call the apiResource to get a handle on a resource that will communicate with the REST API
Then in a file like factories/account-factory.js
angular.module('myApp').factory('AuthRoute', ['apiResource', 'api', function (apiResource, api) {
return apiResource(api.AUTH);
}]);
Now in factories/auth-service.js:
'use strict';
angular.module('myApp').factory('AuthService', ['$q', 'AuthRoute', 'NotificationService', function ($q, AuthRoute, api, NotificationService) {
function _get(creds) {
var deferred = $q.defer();
AuthRoute.get()
.then(
function successCb(results){
deferred.resolve(results);
},
function errCb(){
// cant remember what comes into this function
// but handle your error appropriately here
//NotificationService.redirect(status);
//deferred.reject(data, status);
}
);
return deferred.promise;
}
return {
get:_get
};
}]);
As you can imagine, I haven't been able to test it yet, but this is the basis. I'm going to try create a scenario that will allow me to test this. In the mean time, feel free to ask questions or point out mistakes made
Late Addition
Forgot to add this:
'use strict';
angular.module('myApp').factory('api', ["$http", "$q", function ($http, $q) {
var restApiObj,
promise;
function _getConfiguration() {
if (restApiObj)
return restApiObj;
if (promise)
return promise;
promise = $http.get('/scripts/constants/config.json')
.then(function (data) {
restApiObj = data;
promise = null;
return data;
},
function (data, status) {
restApiObj = null;
promise = null;
});
return promise;
}
return {
URL: _getConfiguration
}
}]);
Continuing with the ui-router scenario
.state('member-list', {
url: '/members?limit=&skip='
templateUrl: '/views/members/list.html',
controller: 'MemberListCtrl',
resolve:{
members: ['$stateParams', 'MembersLoader', function($stateParams,MembersLoader){
return MembersLoader({skip: $stateParams.skip || 0, limit: $stateParams.limit || 10});
}
}
});
factory
.factory('MemberRoute', ['apiResource', function(apiResource){
return apiResource('/members/:id', { id: '#id' });
}])
.factory('MembersLoader', ['MembersRoute', function(MembersRoute){
return function(params){
return MemberRoute.query(params);
};
}])
.factory('MemberFollowRoute', ['apiResource', 'api', function(apiResource, api){
return apiResource(api.FOLLOW_MEMBER, { id: '#id' });
}])
controller
.controller('MemberListCtrl', ['$scope', 'members', 'MemberRoute', 'MemberFollowRoute', function($scope, members, MemberRoute, MemberFollowRoute){
$scope.members = members;
$scope.followMember = function(memberId){
MemberFollowRoute.save(
{ id: memberId },
function successCb(){
//Handle your success, possibly with notificationService
},
function errCb(){
// error, something happened that doesn't allow you to follow memberId
//handle this, possibly with notificationService
}
)
};
$scope.unfollowMember = function(memberId){
MemberFollowRoute.delete(
{ id: memberId },
function successCb(){
//Handle your success, possibly with notificationService
},
function errCb(){
// error, something happened that doesn't allow you to unfollow memberId
//handle this, possibly with notificationService
}
)
};
}]);
With all this code above, you will never need to do any sort of initialization on app start, or in some abstract root state. If you were to destroy your API config every 5 mins, there would be no need to manually re-initialize that object and hope that something isn't busy or in need of it while you fetch the config again.
Also, if you look at MembersRoute factory, the apiResource abstracts/obscures the api.URL() that you were hoping not to have to change everywhere. So now, you just provide the url that you want to make your request to, (eg: /members/:id or api.AUTH) and never have to worry about api.URL() again :)

AngularJS CRUD - export.update() not calling in server controller

I'm using the following Yeoman full stack AngularJS NPM: generator-angular-fullstack
When calling update from the client controller, I receive the following error: Error: undefined is not a function (evaluating 'User.update') I'm expecting to see the following in my Web Inspector Logs:
'5586c4e7214a22b5efbd1672'
'updateUser Called' <-- Never routes to server controller
server/api/route:
//Tried PATCH and PUT
router.patch('/:id', auth.isAuthenticated(), controller.update);
//router.put('/:id', auth.isAuthenticated(), controller.update);
server/api/controller:
exports.update = function(req, res, next) {
console.log('updateUser Called');
};
client/app/controller:
'use strict';
angular.module('demoApp')
.controller('SandboxCtrl', function ($scope, $http, $location, Auth, User) {
$scope.getCurrentUser = Auth.getCurrentUser;
$scope.user = {};
$scope.profiles = {};
$scope.allergens = {};
$http.get('/api/users/me').success(function (user) {
$scope.user = user;
$scope.profiles = user.profiles;
console.log(user.name);
console.log(user.profiles);
});
// Update existing User
$scope.update = function () {
var user = $scope.user;
console.log(user._id);
User.update(function () {
$location.path('/' + user._id);
}, function (errorResponse) {
$scope.error = errorResponse.data.message;
});
};
});
/Client/User/Factory:
'use strict';
angular.module('demoApp')
.factory('User', function ($resource) {
return $resource('/api/users/:id/:controller', {
id: '#_id'
},
{
changePassword: {
method: 'PUT',
params: {
controller:'password'
}
},
update: { //<-- I was missing this!
method: 'PATCH'
},
get: {
method: 'GET',
params: {
id:'me'
}
}
});
});
In AngularJS NPM generator-angular-fullstack, the factory/service is tucked away under /client/components/auth/user.service.js
Added necessary object handle to existing factory solved this issue.
update: { //<-- I was missing this!
method: 'PATCH'
},

How to provide delay in ng-controller

As soon as Html page gets loaded, it calls SuperCategoryController, where i am assigning supercategories to $scope variable.
$scope.SuperCategories = SuperCategoryService.GetSuperCategories();
But as this controller is depends on service, which in turn calls the http request. so at the time pf assignment http request is not completed. so $scope.SuperCategories is getting assiged to undefined.
sampleApp.service('SuperCategoryService', ['$http', function ($http){
var URL = 'http://localhost/cgi-bin/superCategory.pl';
var SuperCategories;
$http({
method: 'POST',
url: URL,
data: "action=GET",
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).
success(function (data) {
alert (data);
if (data != null || data != 'undefined') {
SuperCategories = data;
}
})
.error(function (error) {
alert (error.message);
//$scope.status = 'Unable to retrieve super categories' + error.message;
});
//simply returns the SuperCategories list
this.GetSuperCategories = function () {
//alert (SuperCategories);
return SuperCategories;
}
}]);
sampleApp.controller('SuperCategoryController', ['$scope', 'SuperCategoryService', function ($scope, SuperCategoryService){
$scope.SuperCategories = SuperCategoryService.GetSuperCategories();
$scope.LoadSuperCategoryMapping = function()
{
alert ($scope.SelectedSuperCategory.id);
}
}]);
How to solve this problem in proper way.
I haven't tried this code myself but I would approach a solution using factory and a promise to make sure the data has been loaded. Something along these lines:
sampleApp.factory('SuperCategoryService', ['$http', function ($http){
return {
GetSuperCategories: function () {
var URL = 'http://localhost/cgi-bin/superCategory.pl';
return $http.get(URL);
}
}
}]);
sampleApp.controller('SuperCategoryController', ['$scope', 'SuperCategoryService', function ($scope, SuperCategoryService){
$scope.SuperCategories = function() {
SuperCategoryService.GetSuperCategories()
.then(function(d) {
if (d.data != undefined) {
// Your data should be loaded here
console.log(d.data);
$scope.SuperCategories = d.data;
}
})
.error(function(data, status) {
// Errors here
});
}
}]);

Resources