This is my service:
'use strict';
app
.service('myService', function($http) {
this.getJSON = function() {
return $http.get('someUrl/dataForm').then(function(data){
return data.result;
});
};
});
And in my controller I have:
'use strict'
app.controller('myController', function ($scope, myService) {
myService.getJSON().then(function(data){
$scope.myData =data;
});
console.log($scope.myData);
});
I can see that the http call is successfully returning a JSON value but the console log shows that the value of myData is undefined.
What am I doing wrong ?
Place the console.log inside
myService.getJSON().then(function(data){
$scope.myData =data;
console.log($scope.myData);
});
DEMO
Change the code of your controller:
'use strict'
app.controller('myController', function ($scope, myService) {
myService.getJSON().then(function(data){
$scope.myData =data;
console.log($scope.myData);
});
});
This happen because getJSON is an asycronous method, the request to getJSON method not provoke that javascript wait to response, adding console.log in ".then" will solve your issue.
By the way, with getJSON you are working with a concept named "promises", i let you a link explanatory about that with $http
https://docs.angularjs.org/api/ng/service/$http
Update the code in the controller
'use strict';
app.service('myService', function($http) {
this.getJSON = function() {
return $http.get('someUrl/dataForm').then(function(data){
return data.result;
});
};
});
controller
'use strict'
app.controller('myController', function ($scope, myService) {
myService.getJSON().then(function(data){
$scope.myData =data;
console.log($scope.myData);
});
});
$http.get() returns promise object.
promise object has then(), catch(), finally() methods.
then is called when success, catch when error.
change your service to,
app.service('myService', function($http) {
this.getJSON = function() {
return $http.get('someUrl/dataForm'); //returns promise object
};
});
and controller to,
app.controller('myController', function($scope, myService) {
var promise = myService.getJSON();
//after resolving then method get called
promise.then(function(data) {
$scope.myData = data;
console.log($scope.myData);
});
});
Related
Well, I begin...
I've already a factory that loads the data from JSON files succefully:
FIRST FACTORY:
statisticsModule.factory('globalFactory', ['$http', function($http){
return $http.get('../statistics/php/config_statistics.json')
.success(function(data){
return data;
})
.error(function(err){
return err;
});
}]);
I want:
Read a specific URL that contains this JSON
Inject factory inside another factory that read the data for the URL above.
This factory load the data and returns by console that I want:
SECOND FACTORY:
statisticsModule.factory('statusFactory', ['globalFactory', '$http', function(globalFactory, $http){
return globalFactory.success(function(data){
var deserialize = angular.fromJson(data.config.graph_conf_array.arrayReportBD);
var statusUrl = deserialize[0];
$http.get(statusUrl).success(function(data){
console.log(data);
}).error(function(err){
err;
});
});
}]);
But I want a third task:
Inject data in controller
This is my controller:
statisticsModule.controller('tableController', ['statusFactory', '$scope', '$http', function(statusFactory, $scope, $http){
statusFactory.success(function(){
});
}]);
If I want loads data from Second Factory in my controller, How I do?
Sorry for bad english, and thanks in advance.
First of all don't use .success as it doesn't help in promise chaining. .success doesn't create a new promise it returns the original promise.
First Factory
statisticsModule.factory('globalFactory', ['$http', function($http){
return $http.get('../statistics/php/config_statistics.json')
.then(function(response){
return response;
}, function (error) {
return error.
})
}]);
Second Factory
statisticsModule.factory('statusFactory', ['globalFactory', '$http', function(globalFactory, $http){
return globalFactory.then(function(data){
var deserialize = angular.fromJson(data.config.graph_conf_array.arrayReportBD);
var statusUrl = deserialize[0];
return $http.get(statusUrl);
}).then(function (data) {
return data;
});
}]);
Now in your Controller
statisticsModule.controller('tableController', ['statusFactory', '$scope', '$http', function(statusFactory, $scope, $http){
statusFactory.then(function(data){ // data is the data received after get call to statusUrl
// do something
});
}]);
I want to wait for an http response before exiting angular controller. I have written the following code. But id doesn't work as the controller still exits before the http call is returned. Can anyone help me out to fix this? Thanks in advance.
var app = angular.module('app', []);
app.factory('MyService', function ($http) {
return $http.get('/api/endpoint').then(function(res){
return res.data;
});
});
app.controller('MyController', ['$scope', '$http', 'MyService', function($scope, $http, MyService){
MyService.then(function(data){
$scope.myVarialbe = data;
})
}]);
I would write this as below.
'use strict';
(function () {
function MyService($http) {
function getService() {
var url = yourURL;
return $http({ method: 'GET', cache: false, url: url });
}
return {
getService: getService
};
}
angular.module('app')
.factory('MyService', MyService);
}());
controller code:
MyService.getService().then(function(response) {
});
You can use like this factory just return request response promise and in controller use .then on returned promise.
var app = angular.module('app', []);
app.factory('MyService', ['$http',function($http) {
return {
getData: function() {
return $http.get('/api/endpoint');
}
};
}]);
app.controller('MyController', ['$scope', '$http', 'MyService', function($scope, $http, MyService){
MyService.getData().then(function(response){
$scope.myVarialbe = response.data;
});
}]);
Use $q is better.
Eg:
app.factory('MyService', ['$http', '$q', function($http, $q) {
return {
getData: function() {
var deferred = $q.defer();
$http.get('/api/endpoint')
.then( function(resp) {
deferred.resolve( resp.data );
});
return deferred.promise;
}
};
}]);
app.controller('MyController', ['$scope', 'MyService',function($scope, MyService){
MyService.getData().then(function(data){
$scope.myVarialbe = data;
})
}]);
According to AngularJS, my $http call through a service from my controller is returning undefined?
What seems to be the issue here? I am trying to return the data called, but once passed to the controller the data becomes undefined?
JavaScript
var myStore = angular.module('myStore', [])
.controller('StoreController', ['$scope', 'dataService', function ($scope, dataService) {
$scope.products = dataService.getData();
}])
.service('dataService', ['$http', function($http) {
this.getData = function() {
$http.get('assets/scripts/data/products.json')
.then(function(data) {
return data;
});
};
}]);
HTML
<div class="content">
<ul>
<li ng-repeat="product in products.products">{{product.productName}}</li>
</ul>
</div>
I understand that $http, $q, and $resource all return promises, but I thought I had covered that with .then.
The problem could be that you are not returning the promise created by $http.get in your dataService.getData function. In other words, you may solve your undefined issue by changing what you have to this:
.service('dataService', ['$http', function($http) {
this.getData = function() {
return $http.get...
};
}
If you had multiple calls to $http.get within dataService.getData, here is how you might handle them.
.service('dataService', ['$http', function($http) {
this.getData = function() {
var combinedData, promise;
combinedData = {};
promise = $http.get(<resource1>);
promise.then(function (data1) {
combinedData['resource1Response'] = data1;
return $http.get(<resource2>);
});
return promise.then(function (data2) {
combinedData['resource2Response'] = data2;
return combinedData;
});
};
}]);
A much cleaner way, however, would be to use $q.all
.service('dataService', ['$http', '$q', function($http, $q) {
this.getData = function() {
var combinedData, promises;
combinedData = {};
promises = $q.all([
$http.get(<resource1>),
$http.get(<resource2>)
]);
return promises.then(function (allData) {
console.log('resource1 response', allData[0]);
console.log('resource2 response', allData[1]);
return allData;
});
};
}]);
You're problem does lie in the fact that you are not returning a promise but as you stated in #maxenglander's post you may have multiple http calls involved which means you should start creating and resolving your own promise using $q:
.service('dataService', ['$http', '$q', function($http, $q) {
return $http.get('assets/scripts/data/products.json')
.then(function(data) {
//possibly do work on data
return <<mutated data>>;
});
}];
or if you have multiple http calls and need to do some combination work you can do something $q.all:
.service('dataService', ['$http', '$q', function($http, $q) {
var p1 = $http.get('assets/scripts/data/products.json');
var p2 = $http.get('assets/scripts/data/products2.json');
return $q.all([p1, p2]).then(function(result){
//do some logic with p1 and p2's result
return <<p1&p2s result>>;
});
}];
then in your controller you will need to do:
.controller('StoreController', ['$scope', 'dataService', function ($scope, dataService) {
dataService.getData().then(function(result){
$scope.products = result;
});
}]);
What this allows in your service is now you can do complex calls like say call two webservices inside and wait till they are both complete then resolve the promise.
What I'm trying to express here is that you don't need to return the promise provided by the $http.get function, but since you are doing an async action you DO need to return some promise that will be later fulfilled and acted on.
I have a simple service which grab data from HTTP end point send it back to controller.
I also implemnted caching in the service however, i get this error TypeError: undefined is not a function on this line of code in my controller
myappApi.getItems().then(function(data)
I tried to figure out why i couldn't.
here is the controller code:
.controller('ItemsCtrl',['$scope','myappApi',function($scope, myappApi){
myappApi.getItems().then(function(data){
$scope.items = data;
});
}])
As am using Ioniframework here how i injected my services in the app.js:
angular.module('myApp', ['ionic', 'myApp.controllers', 'myApp.services', 'angular-data.DSCacheFactory'])
and here is the code of my service:
(function() {
'use strict';
angular.module('myApp.services',[]).factory('myappApi', ['$http', '$q', '$ionicLoading', 'DSCacheFactory', myappApi]);
function myappApi($http, $q, $ionicLoading, DSCacheFactory) {
self.itemsCache = DSCacheFactory.get("itemsCache");
//to re-use expired cached data if no internet connection
self.itemsCache.setOptions({
onExpire: function (key, value) {
getItems()
.then(function () {
console.log("items items Cache was automatically refreshed.", new Date());
}, function () {
console.log("Error getting data. Putting expired item back in the cache.", new Date());
self.itemsCache.put(key, value);
});
}
});
function getItems() {
var deferred = $q.defer(),
cacheKey = "items",
itemsData = self.itemsCache.get(cacheKey);
if (itemsData) {
console.log("Found data inside cache", itemsData);
deferred.resolve(itemsData);
} else {
$http.get("services/data.json")
.success(function(data) {
console.log("Received data via HTTP");
self.itemsCache.put(cacheKey, data);
deferred.resolve(data);
})
.error(function() {
console.log("Error while making HTTP call.");
deferred.reject();
});
}
return deferred.promise;
}
return {
getItems: getItems
};
};
})();
Thank you for your time.
Take a look in the angular-cache file CHANGELOG.md :
"- Angular module renamed to angular-cache
- DSCacheFactory renamed to CacheFactory"
You will have to change:
app.js:
instead of 'angular-data.DSCacheFactory' use 'angular-cache'
service.js
instead of 'DSCacheFactory' use 'CacheFactory'
It looks like you've declared the myappApi factory before the myappApi function is actually defined. Try something like:
angular.module('myApp.services',[]).factory('myappApi', ['$http', '$q', '$ionicLoading', 'DSCacheFactory',
function($http, $q, $ionicLoading, DSCacheFactory) {
// myappApi code
}]);
I need help, about added jasmine tast to my factory.
My code is...
---dataService.js---
angular.module('angularAppApp')
.factory('dataService', function($resource){
return $resource(`http://...:3100/posts/:id`, null,
{
'update': { method:'PUT' }
});
})
---onePostCtrl.js ---
angular.module('angularAppApp')
.controller('onePostCtrl', ['$scope', '$http', '$routeParams', 'dataService',
function ($scope, $http, $routeParams, dataService) {
dataService.get ({id: $routeParams.postId}).$promise.then(function(data){
$scope.postInfo = data;
});
}]);
-- main container ---
angular.module('angularAppApp').controller('postCtrl', ['$scope','$http', 'ngDialog', 'dataService','trimService', function ($scope, $http, ngDialog, dataService, trimService) {
//save data to remote server from loaded pop-up
$scope.savePost = function(){
$scope.addFormData.date = $scope.formated_date;
dataService.save($scope.addFormData, function() {
laodData();
});
ngDialog.closeAll();
};
//delete post from remote server
$scope.deletePost = function(article) {
dataService.delete({ id: article._id }, function() {
laodData();
});
};
//edit post from remote server
$scope.updatePost = function (article) {
dataService.update({ id: article._id},article).$promise.then(function() {
laodData();
});
ngDialog.closeAll();
}
}]);
--- mock data ---
angular.module('mock', []).value('items', [{ ... }]
---At index.html I am have loaded mocks scripts---
src="bower_components/angular-mocks/angular-mocks.js"
src="mosk_data/mocks.module.js"
--Jasmine tests is ...
describe("factory of dataService", function (){
var $httpBackend, $http, $q, factory;
beforeEach(module("angularAppApp"));
beforeEach(module('mock'));
beforeEach(function(){
inject(function($injector, _$httpBackend_,_$http_,_$q_){
$q = _$q_;
$http = _$http_;
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', '/items').respond(items);
factory = $injector.get('dataService');
});
afterEach(function () {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
it("Data service", function(){
});
});
Now, I have error "ReferenceError: items is not defined" and cannot ideas how I can test my dataService.
You forgot to inject your value and assign it to a variable in the tests. Try this:
var $httpBackend, $http, $q, factory, items; //declare variable items here (or you can do it inside beforeEach)
beforeEach(module("angularAppApp"));
beforeEach(module('mock'));
beforeEach(function(){
inject(function($injector, _$httpBackend_,_$http_,_$q_, _items_){
$q = _$q_;
$http = _$http_;
//inject the value and assign to your variable
items = _items_
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', '/items').respond(items);
factory = $injector.get('dataService');
});
The Reference error you got was because there was no variable called items. You defined an angular value with name items, but it's not the same as a variable - think of it as it lives "somewhere inside angular guts" and to use it you have to inject it and then use as normal variable.