I'm trying to get data from a server in my AngularJS app, using $http.get. But when I execute the request, it seems to get cancelled by something. It happens with every link I use. Local files are working.
Below the code from Controller.js:
angular
.module('schoolApp')
.controller('configController', [
'apiService', '$http', function (apiService, $http) {
var vm = this;
vm.isActive = isActive;
vm.addPortal = addPortal;
...
function addPortal() {
...
apiService.getServerData('someUrl', "1.0")
.then(function (result) {
var test = result.data;
})
.catch(function (result) {
console.log(result);
});
}
...
And the Service.js:
angular
.module('schoolApp')
.service('apiService', [ '$http', function ($http) {
var service = {
getServerData: getServerData,
};
return service;
function getServerData(portalUrl, appVersion) {
// var url = "http://../.../.svc/GetSetting?alias=...&AppVersion=1.0";
var url = "http://xml.buienradar.nl";
//var url = "test.json";
//var url = "xml.xml";
// "http://" +
// portalUrl +
// "/.../.../.svc/GetSetting?alias=" +
// portalUrl +
// "&AppVersion=" +
// appVersion;
return $http.get(url);
}
}]);
Executing this code will show the alert("ERROR: " + result) from the controller class. Data from the result:
result: Object config: Object data: null headers: (c)
status: -1 statusText: ""
__proto __: Object
Network in browser shows the call is cancelled:
http://i.stack.imgur.com/MJoZM.png
More info:
- I'm using Phonegap (tested without and doesn't work either)
- AngularJS 1.4
Ok, found the answer. I called window.location.reload() in the same function, and that conflicted. So, now I added it to the .then() function in the request.
Related
I've got a employeeController and a employeeFactory in the employeeFactory I receive an employee like this:
function employeeFactory(authenticationFactory,requestFactory,GLOBALS) {
var factory = {};
var vm = this;
vm.employee = {};
factory.getEmployee = function(id) {
data = {"api_token": authenticationFactory.getToken()};
url = GLOBALS.url + 'show/employee/' + id;
requestFactory.post(url, data)
.then(function (response) {
return vm.employee = response.data.result.Employee;
}, function () {
$window.location.assign('/');
});
}
return factory;
}
In my controller I'm trying to receive it like this:
console.log(employeeFactory.getEmployee($routeParams.id));
But the result is null?
When I console.log the response in my requestFactory I receive an employee object. What am I doing wrong?
Reason behind it is, you missed to return promise of requestFactory.post from factory.getEmployee method
Code
factory.getEmployee = function(id) {
data = {"api_token": authenticationFactory.getToken()};
url = GLOBALS.url + 'show/employee/' + id;
return requestFactory.post(url, data)
.then(function (response) {
return vm.employee = response.data.result.Employee;
}, function () {
$window.location.assign('/');
});
}
But even though you do it, you will not able to get value employee object printed. It will print promise object return by $http.post method/ $resource method
For getting hold on that object you need to use .then function over that promise object. like below
employeeFactory.getEmployee($routeParams.id).then(function(employee){
console.log('Employee', employee)
})
We can use deferred api in angularjs for better communication between caller and service.
factory.getEmployee = function(id) {
var deferred = $q.defer();
data = {"api_token": authenticationFactory.getToken()};
url = GLOBALS.url + 'show/employee/' + id;
return requestFactory.post(url, data)
.then(function (response) {
deferred.resolve(response.data.result.Employee);
}, function () {
deferred.reject();
});
return deferred.promise;
}
On your controller:
employeeFactory.getEmployee($routeParams.id).then(function(employee){
console.log('Employee', employee)
},function(){
$window.location.assign('/');
})
By this approach we can notify caller with some messages if your response gets delayed.
For more info see this link.
angular promises
I have an Angular app, and in the controller I need to call a function which makes two http get requests, and I need this function to return these values just when they are resolved. I cannot make them in the $routeProvider resolve because this function needs a value obtained in the same controller.
I show part of the controller:
function myController(info) {
var vm = this;
vm.name = info.data.name;
vm.extra_data = MyService.getExtras(name);
}
And here is part of the code of the service:
function myService($http, $q, API_EVENT1, API_EVENT2) {
return {
getExtras: getExtras
}
function getExtras(name) {
var request1 = API_EVENT1 + '/' + name;
var request2 = API_EVENT2 + '/' + name;
}
}
The function is not complete due to I have tried several methods, but I wasn't successful at all.
My problem is how to return (in getExtras function) both of the results of the requests. I have tried using $q.defer, $q.all and promises, but I'm not able to achieve it.
Using $q.all, for example, I got to retrieve the result, but when I call the function, the object extra_data is undefined, due to the requests have been executed asynchronously.
Thank you in advance for your responses.
I would use $q.all to return combined promise from Service, and process result in controller. e.g.:
function myService($http, $q, API_EVENT1, API_EVENT2) {
return {
getExtras: getExtras
}
function getExtras(name) {
return $q.all([
$http({method: 'GET', url: API_EVENT1 + '/' + name}),
$http({method: 'GET', url: API_EVENT2 + '/' + name})])
);
}
}
function myController(info) {
var vm = this;
vm.name = info.data.name;
MyService.getExtras(name).then(function(data) {
vm.extra_data.first = data[0];
vm.extra_data.second = data[1];
});
}
I have been at this for over 10 hours at this point. It does not make sense to me. I desperately need clarification on what I'm doing wrong. Below is a simple factory function that makes an AJAX call for a JSON file. There are no async. data issues and everything just works. The issue I'm having is that I'm trying to save the returned result and access it later. If the variable is populated, I don't then have to make a second AJAX call, I can simple grab the contents of a local variable. I realize there are other ways of doing this, but I'm particular to using this factory method.
storyDataAsFactory.$inject = ['$log', '$http', '$q'];
angular.module('ccsApp').factory('storyDataAsFactory', storyDataAsFactory);
function storyDataAsFactory($log, $http, $q) {
var storiesCache = [];
function getStories(url) {
url = url || '';
if (url !== '') {
var deferred = $q.defer();
alert('inside getStories, length of storiesCache = ' + storiesCache.length); // this is always zero! Why?
//determine if ajax call has already occurred;
//if so, data exists in cache as local var
if (storiesCache.length !== 0) {
$log.info('Returning stories from cache.');
deferred.resolve(storiesCache);
return deferred.promise;
}
$http({method:'GET', url:url})
.success(function (data, status, headers, config) {
deferred.resolve(data);
})
.error(function (data, status, headers, config) {
deferred.reject(status);
});
return deferred.promise;
} else {
$log.error('(within storyDataAsFactory) Failed to retrieve stories: URL was undefined.');
}
}
return {
stories: storiesCache,
getStories: function(url) {
alert('inside return factory object, length of stories = ' + this.stories.length);
//getStories returns a promise so that routeProvider
//will instantiate the controller when resolved
return getStories(url);
}
};
}
You need to use a promise. I have not ran the code below, but this is the idea:
angular.module('ccsApp').service('storyDataAsFactory', storyDataAsService);
function storyDataAsService($log, $http, $q) {
var storiesCache = [];
function getStories(url) {
url = url || '';
if (url !== '') {
alert('inside getStories, length of storiesCache = ' + storiesCache.length); // this is always zero! Why?
if (storiesCache.length == 0) {
return $http({method:'GET', url:url});
} else {
var deferred = $q.defer();
deferred.resolve(storiesCache);
return deferred.promise;
}
} else {
$log.error('(within storyDataAsFactory) Failed to retrieve stories: URL was undefined.');
}
}
return {
getStories: function(url) {
return getStories(url).then(function(stories) {
// Do whatever
return stories;
});
}
};
}
storyDataAsService.getStories().then(function(stories) {
$scope.stories = stories
})
i am using $timeout in my controller but its not working!
app.controller("Friendsrequests",['$http','$log','$location','$timeout','$scope', function($http,$log,$location,$timeout,$scope){
//getting base url of application
this.baseUrl = function() {
var base_url = window.location.origin;
var pathArray = window.location.pathname;
return base_url;
// return base_url+pathArray;
};
// assigning to a variablebase_url('login/f_request');
var ThroughUrl = this.baseUrl()+'/keon/login/f_request';
//declare a variable
var ata = this;
ata.notifications = [ ] ;
ata.counts=' ';
//sending ajax request
function getNotifications()
{
$http({method: 'POST', url: ThroughUrl,})
.success(function(data) {
// this callback will be called asynchronously
// when the response is available
//assign data to the variable
ata.notifications=data;
ata.counts =data.length;
}).
error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
}
$timeout(function() {
getNotifications();
}, 1000);
}]);
what is the issue .
UPDATED
Just replace
$timeout(function() {
getNotifications();
}, 1000);
with
$interval(function() {
getNotifications();
},1000);
Check Angular's doc
while calling timeout in angularJS just remove Parentheses or brackets ()
$timeout(getNotifications, 1000);
getNotifications function will call after 1000 milliseconds(One second)
I use a angular $http interceptor, to check if a ajax request returns 401 (not authenticated).
If response is 401, the original request gets queued, a login form is shown and after login successfully, it retries the queued requests. This already works with $http, and the source for the angular interceptor is:
define('common.service.security.interceptor', ['angular'], function() {
'use strict';
angular.module('common.service.security.interceptor', ['common.service.security.retryQueue'])
.factory('securityInterceptor', [
'$injector',
'$location',
'securityRetryQueue',
function($injector, $location, securityRetryQueue) {
return function(promise) {
var $http = $injector.get('$http');
// catch the erroneous requests
return promise.then(null, function(originalResponse){
if(originalResponse.status === 401){
promise = securityRetryQueue.pushRetryFn('Unauthorized', function retryRequest(){
return $injector.get('$http')(originalResponse.config);
});
}
return promise;
});
};
}
])
// register the interceptor to the angular http service. method)
.config(['$httpProvider', function($httpProvider) {
$httpProvider.responseInterceptors.push('securityInterceptor');
}]);});
How can I make breeze request using this angular $http interceptor?
Breeze provides a wrapper for the angular $http service in the file "Breeze/Adapters/breeze.ajax.angular.js". So the first idea was to tell breeze to use it:
breeze.config.initializeAdapterInstance("ajax", "angular", true);
Debugging angular.js, it shows that breeze now in fact uses $http, but it does not execute the above registered interceptor. Inside $http, there is an array "reversedInterceptors", which holds the registered interceptors. I log this array to console. If i use $http, the length of this array is one (as expected), but when making request with breeze, this array is empty.
The question is, how can i use this $http interceptor with breeze requests?
Here is the code for breeze.ajax.angular.js, provided by breeze
define('breeze.ajax.angular.module', ['breeze', 'angular'], function (breeze) {
'use strict';
/* jshint ignore:start */
var core = breeze.core;
var httpService;
var rootScope;
var ctor = function () {
this.name = "angular";
this.defaultSettings = {};
};
ctor.prototype.initialize = function () {
var ng = core.requireLib("angular");
if (ng) {
var $injector = ng.injector(['ng']);
$injector.invoke(['$http', '$rootScope',
function (xHttp, xRootScope) {
httpService = xHttp;
rootScope = xRootScope;
}]);
}
};
ctor.prototype.setHttp = function (http) {
httpService = http;
rootScope = null; // to suppress rootScope.digest
};
ctor.prototype.ajax = function (config) {
if (!httpService) {
throw new Error("Unable to locate angular for ajax adapter");
}
var ngConfig = {
method: config.type,
url: config.url,
dataType: config.dataType,
contentType: config.contentType,
crossDomain: config.crossDomain
}
if (config.params) {
// Hack: because of the way that Angular handles writing parameters out to the url.
// so this approach takes over the url param writing completely.
// See: http://victorblog.com/2012/12/20/make-angularjs-http-service-behave-like-jquery-ajax/
var delim = (ngConfig.url.indexOf("?") >= 0) ? "&" : "?";
ngConfig.url = ngConfig.url + delim + encodeParams(config.params);
}
if (config.data) {
ngConfig.data = config.data;
}
if (!core.isEmpty(this.defaultSettings)) {
var compositeConfig = core.extend({}, this.defaultSettings);
ngConfig = core.extend(compositeConfig, ngConfig);
}
httpService(ngConfig).success(function (data, status, headers, xconfig) {
// HACK: because $http returns a server side null as a string containing "null" - this is WRONG.
if (data === "null") data = null;
var httpResponse = {
data: data,
status: status,
getHeaders: headers,
config: config
};
config.success(httpResponse);
}).error(function (data, status, headers, xconfig) {
var httpResponse = {
data: data,
status: status,
getHeaders: headers,
config: config
};
config.error(httpResponse);
});
rootScope && rootScope.$digest();
};
function encodeParams(obj) {
var query = '';
var key, subValue, innerObj;
for (var name in obj) {
var value = obj[name];
if (value instanceof Array) {
for (var i = 0; i < value.length; ++i) {
subValue = value[i];
fullSubName = name + '[' + i + ']';
innerObj = {};
innerObj[fullSubName] = subValue;
query += encodeParams(innerObj) + '&';
}
} else if (value instanceof Object) {
for (var subName in value) {
subValue = value[subName];
fullSubName = name + '[' + subName + ']';
innerObj = {};
innerObj[fullSubName] = subValue;
query += encodeParams(innerObj) + '&';
}
} else if (value !== undefined) {
query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&';
}
}
return query.length ? query.substr(0, query.length - 1) : query;
}
breeze.config.registerAdapter("ajax", ctor);
breeze.config.initializeAdapterInstance("ajax", "angular", true);
/* jshint ignore:end */
});
using the setHttp method works for me to use http interceptors with the breeze angular ajax adapter. in my environment, it looks like this:
(function() {
'use strict';
var serviceId = 'entityManagerFactory';
angular.module('app').factory(serviceId, ['$http', emFactory]);
function emFactory($http) {
var instance = breeze.config.initializeAdapterInstance("ajax", "angular");
instance.setHttp($http);
...
}
})();
the only place I've really found any information about this is in the release notes for 1.4.4 on the download page. I don't really understand what this does. i'm sure one of the breeze guys will have a better explanation.
You have to call setHttp($http) as explained by #almaplayera. Please mark his as the correct answer.
Here's why that is necessary.
By default, the breeze angular ajax adapter initializes itself with whatever instance of $http is available. Unfortunately, at the time that most scripts are loading, the $http instance for YOUR APP hasn't been created. That won't happen until your module loads ... which typically happens long after breeze loads.
So rather than create an adapter that won't work at all, breeze spins up its own instance of $http and wires the angular ajax adapter to that instance.
If your code doesn't do anything special, this works fine. It's not optimal; you'll get one extra $digest cycle than necessary. But it works for most people and let's admit that there is more than enough configuration noise to deal with as it is.
But you ARE doing something special. You're configuring a very specific instance of $http, not the one that breeze created for itself.
So you have to tell breeze to use YOUR instance of $http ... and that's what happens when you call setHttp($http);
Thanks to this feedback I have updated the breeze documentation on ajax adapters to describe how to configure for an Angular app.