I'm trying to set a variable as the data object returned from a http request in angular, but the variable never sets to even if it is in the $scope unless it is nested within the success function. For example, if I do this in the controller :
$scope.hello = [];
var getAppointmentsurl = './dbscripts/getAppointments.php';
$http({method: 'GET', url: getAppointmentsurl}).success(function(data) {
$scope.hello = data;
});
console.log($scope.hello);
}
Hello is blank... so I set it up in services.js like this :
this.getCalendarData=function(){
var hello = [];
var getAppointmentsurl = './dbscripts/getAppointments.php';
$http({method: 'GET', url: getAppointmentsurl}).success(function(data) {
hello = data;
});
return hello;
}
but still hello is blank. Am I missing something obvious?
edit --
this.getCalendarData=function(){
var getAppointmentsurl = './dbscripts/getAppointments.php';
return $http({method: 'GET', url: getAppointmentsurl}).success(function(data) {
return data;
});
}
This is asynchronus call we have to return data like above.
To elaborate on Akash's correct answer, here's an example of how it should work.
In your view you should add logic to show the data only when hello exists. i.e. ng-if="hello"
controller:
ServiceName.getCalendarData().then(function(response) {
$scope.hello = response;
});
service:
this.getCalendarData = function() {
return $http.get('path/to/response/').success(function(data) {
return data;
});
}
As you put the api call as a method in the service, returning data from the service wont resolve yet, So in the controller the service return will only be a promise
serviceName.getCalendarData().then(function(data){
//Success data
},function(){});
Service code must return like the below code and here you will get the entire response object,
return $http({method: 'GET', url:getAppointmentsurl});
One other way to get the data directly resolved stripping of the other properties is returning from service like this,
return $http({method: 'GET', url:getAppointmentsurl}).success(function(data){
return data;
});
Related
Been scratching my head for weeks on this particular part of my code. What I have is a simple custom service that would fetch my data via ajax, I then perform a post process and lastly I want to return that data back to my controller. Even tough my service is creating my object correctly nothing ever gets back to my controller.
Ive tried using a "deferred.promise" method, which does seems to return data back to the controller but in a $$state object that I cannot access via the controller for some strange reason. This is a whole other issue.
I just need a simpleway to return data to my controller but all of the post process must be handled in my service. Would anyone know if this is possible?
Here is what i got.
My service:
var app = angular.module('myApp', []);
app.factory('MyService', function($http, $q, $timeout){
var My_Stored_Data = {}
return {
load_my_data_service: function(){
$http({
method: 'GET',
url: 'AJAX PATH',
headers: { "Accept": "application/json;odata=verbose;charset=utf-8"}
}).then(function(data){
//post-process my data before returning it to the controller $scope.return_my_data_here
My_Stored_Data = data;
My_Stored_Data.data_result_1 = My_Stored_Data.data_result_1.split("\r\n");
My_Stored_Data.data_result_2 = My_Stored_Data.data_result_2.split("\r\n");
console.log(My_Stored_Data)//logs shows the that "My_Stored_Data" has processed my data correctly.
return My_Stored_Data //Return my data tot he controller $scope.return_my_data_here.
});
}
}
});
My controller:
app.controller('MyController', function ($scope,$q,MyService) {
$scope.fetch_my_data = function(){
$scope.return_my_data_here = MyService.load_my_data_service();
}
$scope.fetch_my_data() //Initiate on page load
});
#Ali Baig is correct. You need the return as he has pointed out. But the object returned is a promise and not the raw data as you are expecting so you also need this:
app.controller('MyController', function ($scope,$q,MyService) {
$scope.fetch_my_data = function(){
// MyService.load_my_data_service() will return a promise.
$scope.return_my_data_here = MyService.load_my_data_service();
// Use .then() to do something with that promise.
// NOTE: This code will run asynchronously.
$scope.return_my_data_here.then(function(data){
$scope.actualData = data;
console.log($scope.actualData);
});
}
$scope.fetch_my_data() //Initiate on page load
});
I believe you are missing a return statement just before $http({..
return {
load_my_data_service: function(){
return $http({
method: 'GET',
url: 'AJAX PATH',
headers: { "Accept": "application/json;odata=verbose;charset=utf-8"}
}).then(function(result){
return result.data; //to make it cleaner, just return the promise itself to your controller..
});
}
}
This will resolve your service problems. And then in your controller, use
$scope.return_my_data_here = {};
MyService.load_my_data_service().then(function(data){
var My_Stored_Data = data;
My_Stored_Data.data_result_1 = My_Stored_Data.data_result_1.split("\r\n");
My_Stored_Data.data_result_2 = My_Stored_Data.data_result_2.split("\r\n");
$scope.return_my_data_here = My_Stored_Data;
});
I have an API call that's working great, but I'd like to use it on several controllers so I moved it to it's own service. I'm running into what looks like a classic Scope issue or a misunderstanding of Angular's digest cycle.
'use strict';
myApp.factory('Stuff',['$http', function ($http) {
var Stuff = {};
Stuff.data = {};
Stuff.api = 'http://localhost:8080/api/';
Stuff.getStuff = function() {
var http_stuff_config = {
method: 'GET',
url: Stuff.api + 'stuff/'
};
$http(http_stuff_config).then(function successCallback(response) {
Stuff.data = (response.data);
console.log(Stuff.data); // Returns populated object.
},function errorCallback(response) {
console.log(response.statusText);
});
};
Stuff.getStuff();
console.log(Stuff.data); // Returns empty object.
return Stuff;
}]);
myApp.controller('appController', ['$scope','Stuff',function($scope,Stuff) {
$scope.stuff = Stuff;
console.log($scope.stuff.data); // Returns empty object.
$scope.stuff.getJobs();
console.log($scope.stuff.data); // Returns empty object.
}]);
Here's the big clue. The essential output of above, in order is...
empty object (in service after calling method)
empty object (in controller before calling method)
empty object (in controller after calling method)
populated object (in method execution from service)
populated object (in method execution from controller)
So somewhere between the scope of the getStuff() method and Angular's order of operations, I'm doing something remarkably foolish. Thank you in advance.
You need to add returns on your service, or else the promise will not be returned to the controller. It is not good practice to just store the returns in your services AND NOT return the result to the controller.
This is considered bad practice because, any time you update the data on the service everyone will need to apply $scope.$watch to the service to look for updates. This can be very expensive in large scale apps.
The best Idea is to return the data to the calling controller (if you do not need to cache it, this we can talk about later) and let the controller access it via the promise service.getthing().then(function(result){});
myApp.factory('Stuff',['$http', function ($http) {
var Stuff = {};
Stuff.data = {};
Stuff.api = 'http://localhost:8080/api/';
Stuff.getStuff = function() {
var http_stuff_config = {
method: 'GET',
url: Stuff.api + 'stuff/'
};
return $http(http_stuff_config).then(function successCallback(response) {
return response.data;
console.log(Stuff.data); // Returns populated object.
},function errorCallback(response) {
console.log(response.statusText);
});
};
Stuff.getStuff();
console.log(Stuff.data); // Returns empty object.
return Stuff;
}]);
myApp.controller('appController', ['$scope','Stuff',function($scope,Stuff) {
$scope.stuff = Stuff;
console.log($scope.stuff.data); // Returns empty object.
$scope.stuff.getJobs().then(function(result) {$scope.stuff = result; console.log(result);});
console.log($scope.stuff.data); // Returns empty object.
}]);
I recommend you not to store the result inside the service itself (Stuff.data). Just return your data in the getStuff function and let the appController's scope store the data instead.
remember that $scope.stuff.getJobs() is async
(meaning you can't actually call console.log($scope.stuff.data) on the next line and get the data)
Now if you had a view, with something like <span ng-bind="stuff.data.property"> you could see it work just fine because the view will update by itself when the async function is done. (this is part of angular)
You need to understand that when you run $http, it is making an AJAX request. therefore it will not return an result immediately.
Therefore, if you attempt to use the data coming from $scope.stuff.getJobs(); immediate after invoking this function, you are likely to get nothing.
What you should do is to have your Stuff.getJobs() return a promise, and use promise.then(your own success handler) to correctly handle the returned response.
I have cleaned up your code a little bit. The following is a running sample of your code retrieving data from Yahoo Weather API.
You can play with it on CODEPEN.
html:
<div ng-app="myApp" ng-controller="appController">
<p>{{data}}</p>
</div>
JS:
var myApp = angular.module("myApp", []);
myApp.factory('Stuff',['$http', function ($http) {
var Stuff = {};
Stuff.data = {};
//sample yahoo weather api
Stuff.api = 'https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22nome%2C%20ak%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys';
Stuff.getData = function() {
var http_stuff_config = {
method: 'GET',
url: Stuff.api + 'stuff/'
};
return $http(http_stuff_config);
};
return Stuff;
}]);
myApp.controller('appController', ['$scope','Stuff',function($scope,Stuff) {
$scope.data = "$http service not ran";
var uncompletedAjaxCall = Stuff.getData();
uncompletedAjaxCall.then(
function(responseData){
$scope.data = responseData;
},
function(errorMsg){}
);
}]);
I have a problem with my Angular Service. I have two controllers and one service. Basically the first controller gets data via AJAX call and store that data on the service. The second controller then access that data via service. I have successfully passed the data from the 1st controller to the service however, when I access the data from the 2nd controller it returns nothing.
I have one view with 2 controllers by the way.
Thanks
Service
app.service('SharedDataService', function () {
// Holds subtask that will be passed to other controllers
// if SharedDataService is invoke.
var _subTask = {};
return {
subTask : _subTask
};
});
Controller 1
app.controller('MainCategoryController',function($scope,$http,SharedDataService){
$scope.loadSubtask = function(m_uid){
$http({
method: 'POST',
url: $locationProvider + 'query_stasks',
data: {
m_uid: m_uid
}
}).then(function successCallback(response) {
SharedDataService.subTask = response.data;
},function errorCallback(response){
});
}
}
Controller 2
app.controller('SubTaskController',function($scope,$http,$location,$rootScope,SharedDataService){
$scope.$watch('SharedDataService.subTask', function(newValue,oldValue){
console.log("ni sud');");
if (newValue !== oldValue) {
$scope.subTasks = newValue;
}
return SharedDataService.subTask;
});
}
Because SharedDataService is not on $scope, the first argument of the $watch method needs to be a watchExpression function instead of an Angular expression string.
app.controller('SubTaskController',function($scope,$http,$location,$rootScope,SharedDataService){
$scope.$watch(
function watchExpression() {return SharedDataService.subTask},
function listener (newValue,oldValue){
console.log("ni sud");
if (newValue !== oldValue) {
$scope.subTasks = newValue;
}
}
});
});
For more information, see AngularJS $rootScope.scope API Reference - $watch.
May be you should save the value use object in service.In my project, i always do like this:
app.service('SharedDataService', function () {
var service = {};
service._subTask = '';
service.toogle_sub_task = function(v){
if(v){
service._subTask = v;
}
return service._subTask;
}
return service;
});
Then, in your controller. You should call service.toogle_sub_task to set and get value. Just give it a try.Best wishes.
you have to write a method to store the data into service and return the data from service
app.factory('SharedDataService', function () {
// Holds subtask that will be passed to other controllers
// if SharedDataService is invoke.
var _subTask = [];
function setSubTask = function(data){
_subTask = data;
};
return {
subTask : _subTask,
setSubTask:setSubTask
};
});
and in controller call
SharedDataService.setSubTask(response.data);
to set the data...
try it
app.service('SharedDataService', function () {
this._subTask ={};
});
// keep code same 1st controller
app.controller('MainCategoryController',function($scope,$http,SharedDataService){
$scope.loadSubtask = function(m_uid){
$http({
method: 'POST',
url: $locationProvider + 'query_stasks',
data: {
m_uid: m_uid
}
}).then(function successCallback(response) {
SharedDataService._subTask = response.data;
},function errorCallback(response){
});
}
}
// 2nd controller
app.controller('SubTaskController',function($scope,$http,$location,$rootScope,SharedDataService){
console.log(SharedDataService._subTask );
});
The best practice is to make any $http/resource calls in services and not in controller or directives directly. This makes the code more module and less interlinked.
You should ideally have
app.factory('SharedDataService', function ($http) {
var subtasks = [];
var saveSubtasks = function(sub){
subtasks = sub;
console.log(subtasks)
}
var tasks = {
loadSubtasks : function(m_uid){
$http({
method: 'POST',
url: $locationProvider + 'query_stasks',
data: {
m_uid: m_uid
}
}).then(function(data){
saveSubtasks(data);
});
},
getSubtasks : function(){
return subtasks;
}
}
return tasks;
});
and use it like
app.controller('SharedDataService',function($scope,SharedDataService){
$scope.load = function(val){
SharedDataService.loadSubtasks(val);
}
});
app.controller('SubTaskController',function($scope,SharedDataService){
$scope.get = function(){
$scope.subtasks = SharedDataService.getSubtasks();
console.log($scope.subtasks);
}
});
Hello guys I really need help and advice on this factory and controller issue I am having.
I have a factory that gets data from the server
sp.factory('homeFeed',['$window','$http','auth',function($window,$http,auth){
var url = auth.url;
var version = auth.version;
var HomeFeed = {};
HomeFeed.getFeeds = function(user){
//setting variable for get request on home feed
var req = {
method: 'GET',
url: url + version + '/Feed',
headers: {
'Content-Type': 'application/json; charset=utf-8',
'Authorization': 'Bearer ' + token
},
}
return $http(req).success(function(res){
return res;
});
};
return HomeFeed;
}]);
controller--
sp.controller('HomeCtrl',['$scope','homeFeed','$window',function($scope,homeFeed,$window){
//getting all the home feed data
$scope.feeds = homeFeed.getFeeds(JSON.parse($window.localStorage['SP-User']))
}]);
however, after the respond from the server, my view is not updated and the $scope.feeds is not updated as well. Greatly appreciate your help
As you are doing async $http call then that data would not be available at that instance of time. It would be available when ajax call succeeded. You need to use .then function which will create a promise chain and will execute a function when .success function returns a data.
Controller
sp.controller('HomeCtrl',['$scope','homeFeed','$window',
function($scope,homeFeed,$window){
//getting all the home feed data
homeFeed.getFeeds(JSON.parse($window.localStorage['SP-User']))
.then(function(data){
$scope.feeds = data
});
}
]);
I have an factory that gets data from my backend:
as.factory("abbdata", function GetAbbData($http,$rootScope,$routeParams,$q) { //$q = promise
var deffered = $q.defer();
var data = [];
var abbdata = {};
abbdata.async = function () {
$http.get($rootScope.appUrl + '/nao/summary/' + $routeParams['id']).success(function(d) {
data = d.abbData;
deffered.resolve();
});
return deffered.promise;
};
abbdata.data = function() {
return data;
};
return abbdata;
});
A call my factory like this in my controller:
abbdata.async().then(function() {
$scope.abbData = abbdata.data(); //Contains data
});
When I do a console.log($scope.abbData) outside my service call, just underneath, the result Is undifined. Why? Should not the $scope.abbData contain the data from my service after I call it?
EDIT:
You need to pass the data that should be returned into the resolve function like this:
deffered.resolve(data);
EDIT:
To get the data in the controller do this:
abbdata.async().then(function(data) {
$scope.abbData = data; //Contains data
});
Why don't you simply return that value from the async call in the first place?
You can chain promises so by attaching a success handler in your factory and returning a value from that you can simplify your code to:
as.factory("abbdata", function GetAbbData($http,$rootScope,$routeParams) {
return {
async: function () {
return $http.get($rootScope.appUrl + '/nao/summary/' + $routeParams['id']).success(function(d) {
return d.data.abbData;
});
}
}
});
And then use it like
abbdata.async().then(function(data) {
$scope.abbData = data; //Contains data
});
if you console.log($scope.abbData) outside the service call it should show undefined, since the call is asynchronous.
abbdata.async().then(function() {
$scope.abbData = abbdata.data(); //Contains data
});
console.log($scope.abbData) // this should show undefined
The console.log($scope.abbData) just after setting the abbData should show the data
abbdata.async().then(function() {
$scope.abbData = abbdata.data(); //Contains data
console.log($scope.abbData) // this should show the data
});
EDIT
you can use abbData from your service call like for example
angular.module('myApp', []).controller('HomeCtrl', function($scope, abbdata){
var updateUI;
$scope.abbData = [];
abbdata.async().then(function() {
$scope.abbData = abbdata.data(); //Contains data
updateUI();
});
updateUI = function(){
//do something with $scope.abbData
}
});
EDIT 2
On response to your query, I would do something like,
angular.module('myApp', [])
.controller('JobsCtrl', function($scope, $jobService) {
$scope.jobs = [];
$jobService.all().then(function(jobs) {
$scope.jobs = jobs;
});
})
.service('$jobService', function ($q, $http) {
return {
all: function () {
var deferred = $q.defer();
$http({
url: 'http://url',
method: "GET"
}).success(function (data) {
deferred.resolve(data);
}).error(function () {
deferred.reject("connection issue");
});
return deferred.promise;
}
}
});
associated view
<body ng-app = "myApp">
<div ng-controller = "JobsCtrl">
<div ng-repeat="job in jobs track by job.id">
<a href="#/tab/jobs/{{job.id}}" class="item item-icon-right">
<h2>{{job.job_name}}</h2>
<p>DUE DATE: {{job.job_due_date}}</p>
</a>
</div>
<div>
</body>
Here the service an all function which returns a promise, i.e. it will notify when data is fetched.
in the controller the service is called and as soon the service call is resolved the $scope.jobs is assigned by the resolved data.
the $scope.jobs is used in the angular view. as soon as the jobs data are resolved, i.e. $scope.jobs is assigned, the view is updated.
hope this helps
I had a quick look, I have 2 ideas:
First theory: your service is returning undefined.
Second theory: you need to run $scope.$apply();
See this fiddler: https://jsfiddle.net/Lgfxtfm2/1/
'use strict';
var GetAbbData = function($q) {
//$q = promise
var deffered = $q.defer();
var data = [];
var abbdata = {};
abbdata.async = function () {
setTimeout(function() {
//1: set dummy data
//data = [200, 201];
//2: do nothing
//
//3: set data as undefined
//data = undefined;
deffered.resolve();
}, 100);
return deffered.promise;
};
abbdata.data = function() {
return data;
};
return abbdata;
};
var abbdata = GetAbbData(Q)
abbdata.async().then(function() {
console.log(abbdata.data()); //Contains data
});
I have stripped away a lot of dependencies and replaced $q with Q just for my own ease.
In the above example, I first attempted to run the code with dummy data, the console output the expected data, then I tried to not assign the data, and I get an empty array. This is why I assume that if you are seeing 'undefined' you must be explicitly setting the value to 'undefined'.
That aside, I also noticed that you were testing the result by reading directly from $scope. I know that when not inside the angular scope, doing operations on the $scope object does not necessarily happen in a timely manner, and typing $scope.$apply() usually fixes this. Usually, when using $http, angular keeps you in the appropriate scope, but you are creating your own promise using $q so this could be another potential issue.
Finally, the other two answers have pointed out that you are not using promises in the standard way. Although your code works fine, it is not normal to set your data directly onto your service and retrieve it from there. You can keep your service stateless by simply resolving your promise with the data that you want to process in the then method as shown by the answers by Anzeo and Markus.
I hope I was able to find the solution, good luck.
Dipun
as.factory("abbdata", function GetAbbData($http,$rootScope,$routeParams,$q) { //$q = promise
var deffered = $q.defer();
var data = [];
var abbdata = {};
abbdata.async = function () {
$http.get($rootScope.appUrl + '/nao/summary/' + $routeParams['id']).success(function(d) {
data = d.abbData;
deffered.resolve(data);
});
return deffered.promise;
};
abbdata.data = function() {
return data;
};
return abbdata;
});