AngularJS: Directive to controller communication: $(http).get(...).success is not a function - angularjs

I am trying to send data from factory to a controller but I get the following error:
$(http).get(...).success is not a function
Factory code:
app.factory('sportsFactory', ['$http', function($http) {
return $http.get('data/sports.json')
.success(function(data) {
return data;
})
.error(function(err) {
return err;
});
}]);
Controller code:
app.controller('NavbarController',['$scope', 'sportsFactory',
function($scope, sportsFactory){
sportsFactory.success(function(data){
$scope.sports = data;
});
}]);
If I pass a data without using $http it works!

it is better to create a factory method instead of returning one http request, because that way you can use same factory for several occasions like different http requests for example. But in here this factory only usable for this http request only. So create a function and call that method inside controller.
app.factory('sportsFactory', ['$http', function($http) {
return {
sendReq: function() {
return $http.get('data/sports.json')
}
}
}]);
Note that you don't have to return the success inside the factory since the controller handling the response/promise.
call sendReq method from the controller like this
app.controller('NavbarController', ['$scope', 'sportsFactory',
function($scope, sportsFactory) {
sportsFactory.sendReq().success(function(data) {
$scope.sports = data;
});
}
]);
Note that success is not available since angular 1.6. so beware of your version. if its a latest version use then instead of success like this
app.controller('NavbarController', ['$scope', 'sportsFactory',
function($scope, sportsFactory) {
sportsFactory.sendReq().then(function(response) {
$scope.sports = response.data; // data comes under data property in then
});
}
]);

Change your factory code just return the http promise, and handle it in your controller.
app.factory('sportsFactory', ['$http', function($http) {
return $http.get('data/sports.json')
}]);
If you return a promise from the service, you can handle both success and error callbacks in your controller.
Your controller will be,
app.controller('NavbarController',['$scope', 'sportsFactory',
function($scope, sportsFactory){
sportsFactory.then(function(data) {
$scope.sports = data;
})
.error(function(err) {
console.log(err);
});
}]);
Use, then instead if success since success is deprecated in the latest versions.

app.factory('sportsFactory', ['$http', function($http) {
return $http.get('data/sports.json')
}]);
and in controller
app.controller('NavbarController',['$scope', 'sportsFactory',
function($scope, sportsFactory){
sportsFactory.then(function(data){
$scope.sports = data;
});
}]);

Related

How to call $http.get() in Service using AngularJS

I want to inject Service in a controller. The Service will return $http.get() method.
Error : [$injector:unpr] http://errors.angularjs.org/1.6.4/$injector/unpr?p0=JsonFilterProvider%20%3C-%20JsonFilter
Please suggest whats wrong in my code?
<script>
var app = angular.module("myApp", []);
app.controller("myCntlr", ['$scope', 'myhttpService', function ($scope, myhttpService) {
$scope.myHttpMessage = myhttpService.httpGetService();
}]);
app.service("myhttpService", ['$http', '$scope', function ($http, $scope) {
this.httpGetService = function () {
console.log("httGetService");
$http.get('https://reqres.in/api/users').then(function (successResponse) {
console.log("http Get");
return successResponse;
}, function (errorResponse) {
console.log("http Get Error");
return errorResponse
});
};
}]);
</script>
<div ng-app="myApp" ng-controller="myCntlr">
<p>Http Message:{{myHttpMessage|Json}}</p>
</div>
You can not inject $scope in service. that's not allowed. Instead, you can return promise from service and process inside controller something like this.
app.service("myhttpService",['$http', function ($http) {
this.httpGetService = function () {
return $http.get('https://reqres.in/api/users');
}
}]);
app.controller("myCntlr", ['$scope', 'myhttpService', function ($scope, myhttpService) {
myhttpService.httpGetService().then(function(response){
$scope.myHttpMessage = response.data;
}, function(error){
//do something on failure
});
}]);
The actual issue is you are not getting the response from your service. So the json filter throws an error
<p>Http Message:{{myHttpMessage | json}}</p>
Make sure yo return the result back from the service with a return command.
return $http.get('https://reqres.in/api/users').then(function (successResponse)

AngularJS Ctrl As Syntax with Services

I'm migrating my Angular 1.x code to use the newer, more preferred syntax of avoiding using $scope and using the controller as syntax. I'm having an issue with getting data from a service though.
Here's my example:
var myApp = angular.module('myApp', []);
myApp.controller('MainCtrl', ['$http', '$location', 'userService',
function($http, $location, userService) {
this.name = 'John Doe';
// this.userData = {
// }
this.userData = userService.async().then(function(d) {
return d;
});
console.log(this.userData);
}
]);
myApp.service('userService', function($http) {
var userService = {
async: function() {
// $http returns a promise, which has a then function, which also returns a promise
var promise = $http.get('https://jsonplaceholder.typicode.com/users').then(function(response) {
// The then function here is an opportunity to modify the response
// console.log(response);
// The return value gets picked up by the then in the controller.
return response.data;
});
// Return the promise to the controller
return promise;
}
};
return userService;
});
<body ng-app="myApp">
<div id="ctrl-as-exmpl" ng-controller="MainCtrl as mainctrl">
<h1>Phone Numbers for {{mainctrl.name}}</h1>
<button ng-click="">newest</button>
<p>{{mainctrl.userData}}</p>
<ul>
<li ng-repeat="users in mainctrl.userData">{{users.phone}} -- {{users.email}}</li>
</ul>
</div>
</body>
This issue I'm having is that the data returned from the userService.async is an object that I can't seem to drill down thru to get the data from, as the data is a child of $$state, which can't seem to be used in the view.
If this isn't the proper way to use services in the Controller As/$scope-less syntax, what is the proper way?
Live example here: http://plnkr.co/edit/ejHReaAIvVzlSExL5Elw?p=preview
You have a missed an important part of promises - when you return a value from a promise, you return a new promise that will resolve to this value.
The current way to set the data returned from a promise to a local variable in your controller is this:
myApp.controller('MainCtrl', ['$http', '$location', 'userService',
function($http, $location, userService) {
this.name = 'John Doe';
userService.async().then(function(d) {
this.userData = d;
});
}
]);
But now you are in a catch because of the scope of this, so it is common to use a "placeholder" variable for the controller this scope.
myApp.controller('MainCtrl', ['$http', '$location', 'userService',
function($http, $location, userService) {
var $ctrl = this; // Use $ctrl instead of this when you want to address the controller instance
$ctrl.name = 'John Doe';
userService.async().then(function(d) {
$ctrl.userData = d;
});
}
]);
this.userData = userService.async().then(function(d) {
return d;
});
In this bit of code this.userData is actually being defined as a promise. If you want the data that is being returned, you need to use the d parameter from your .then function like so:
userService.async().then(function(d){
this.userData = d;
//a console.log() here would determine if you are getting the data you want.
});
Edit
I just noticed in your Service that you are already using .data on your response object.
Honestly, my best advice to you would be to just return the promise from the http.get() call inside of your service like this:
myApp.service('userService', function($http) {
var userService = {
async: function() {
return $http.get('https://jsonplaceholder.typicode.com/users');
}
};
return userService;
});
And then you could use something like this to capture and utilize the response data:
userService.async().then(function(response){
this.userData = response.data;
);
This may be a bit cleaner of a solution

How to use 'Controller as' with $http in Angular

I'm trying to load some data through $http to prefill a profile form. Unfortunately all the examples I find online use the $scope-approach rather than 'Controller as'-approach (which I'm using to make future transition to Angular 2 easier). These examples assign the $http response to the '$scope' variable, which is not possible when using 'this'.
After a lot of fiddling I managed to get it to work by adding a temp variable
var temp = this;
to which I can assign the $http response when it successfully returns.
angular.module('angularUserApp')
.factory('ajax',['$http',function($http){
return {
getProfile: function(){
return $http.get('/ajax/user/profile')
.then(function(response){
return response.data.data.profile;
});
}
}
}])
.controller('userProfileCtrl', ['ajax', function (ajax) {
var temp = this;
ajax.getProfile().then(function(response){
temp.profile = response;
});
}]);
Is there a more elegant approach?
Your approach for using controllerAs is correct. Just a few advices though, better alias the this to a variable vm, which stands for viewModel instead of temp, and name your service semantically: userService instead of ajax:
angular.module('angularUserApp')
.factory('userService', function ($http){
return {
getProfile: function () {
return $http.get('/ajax/user/profile')
.then(function (response){
return response.data.profile;
});
}
}
})
.controller('userProfileCtrl', function (userService) {
var vm = this;
userService.getProfile().then(function (response) {
vm.profile = response;
});
});
One of the design ideas of angular is that you can use $scope. Simply inject $scope into your controller, like you did with your ajax service and set the profile response to the $scope variable ($scope.profile = response;).
As a result you would get something like:
angular.module('angularUserApp')
.factory('ajax',['$http',function($http){
return {
getProfile: function(){
return $http.get('/ajax/user/profile')
.then(function(response){
return response.data.data.profile;
});
}
}
}])
.controller('userProfileCtrl', ['ajax', '$scope', function (ajax, $scope) {
ajax.getProfile().then(function(response){
$scope.profile = response;
});
}]);
// In your template
<div ng-controller="userProfileCtrl">
<div ng-bind="profile.name"></div>
</div>

Content of an XML File with $http not available outside the .succes() context

I have a service xmlService which uses the $http service to read an XML-File. Everything is working fine, but when I use my xmlService in one of my controllers it returns an empty object, although the $http.get() is successfull. I have no idea whats the problem.
Update:
I understood that the $http-call is asyncronous thus I have to use the $q service. I'm not sure if I understood the $q API correctly because my updated code doesn't work either. I also read an tutorial like this one: http://www.bennadel.com/blog/2612-using-the-http-service-in-angularjs-to-make-ajax-requests.htm - But I can't find the mistake, because I probably didn't understand something.
My Service
angular.module('tvc.Services.Xml', []);
angular.module('tvc.Services.Xml')
.service('xmlService', ['$http', '$log', '$q', 'x2js', function($http, $log, $q, x2js) {
return function(file) {
var deferred = $q.defer(),
parsedFile = {};
$http
.get(file).success(function(data) {
parsedFile.fileContent = data;
parsedFile.json = x2js.xml_str2json(data);
deferred.resolve(parsedFile);
})
.error(function(data) {
$log.warn('Unable to load: ' + file);
});
return deferred.promise;
};
}]);
console.log(parsedFile); returns:
{
fileContent: '<xml>...</xml>',
json: {..},
__prototype__: {...}
}
My Controller
.controller('KeyaccountsController', ['$scope', 'xmlService', function($scope, xmlService) {
$scope.keyaccounts = {};
xmlService('assets/xml/ops_merge_data2.xml').then(function(data) {
$scope.keyaccounts = data;
});
console.log($scope.keyaccounts);
}]);
console.log($scope.keyaccounts); returns:
{}
Since the $http.get() is asynchronous, the return is happening before the success happens, and thus parsedFile is undefined.
You either need to return the promise (i.e., return $http.get(file) and then do all of the logic that you're doing in your controller, or use the angular $q service, like this:
angular.module('tvc.Services.Xml', []);
angular.module('tvc.Services.Xml')
.service('xmlService', ['$http', '$log', 'x2js', '$q', function($http, $log, x2js, $q) {
return function(file) {
var deferred = $q.defer();
var parsedFile = {};
$http
.get(file).success(function(data) {
parsedFile.fileContent = data;
parsedFile.json = x2js.xml_str2json(data);
deferred.resolve(parsedFile)
})
.error(function(data) {
$log.warn('Unable to load: ' + file);
});
return deferred.promise;
};
}]);
And then your controller would be like:
.controller('KeyaccountsController', ['$scope', 'xmlService', function($scope, xmlService) {
xmlService('assets/xml/ops_merge_data2.xml').then(function(data) {
$scope.keyaccounts = data;
console.log($scope.keyaccounts);
});
}]);

Problems using $http inside a Service

I have a basic data Service which will be used across Controllers. But I'm having an issue grabbing some data that's been added via $http.
Service:
angular.module('core').service('FormService', ['$http', function($http) {
var _this = this;
_this.dropdownData = {
contactTimes: ['Anytime','Morning','Afternoon','Evening'],
industries: {},
};
$http.get('/json').success(function(resp){
_this.dropdownData.industries = resp.industries;
});
}]);
Controller:
angular.module('core').controller('SignupController', ['$scope', '$http', '$state', 'FormService', function($scope, $http, $state, FormService) {
console.log(FormService.dropdownData); // Shows full object incl industries
console.log(FormService.dropdownData.industries); // empty object {}
}]);
How do I get FormService.dropdownData.industries in my controller?
Create a service like below
appService.factory('Service', function ($http) {
return {
getIndustries: function () {
return $http.get('/json').then(function (response) {
return response.data;
});
}
}
});
Call in controller
appCtrl.controller('personalMsgCtrl', ['$scope', 'Service', function ($scope, Service) {
$scope.Industries = Service.getIndustries();
}]);
Hope this will help
Add a method to your service and use $Http.get inside that like below
_this.getindustries = function (callback) {
return $http.get('/json').success(function(resp){
_this.dropdownData.industries = resp.industries;
callback(_this.dropdownData)
});
};
In your controller need to access it like below.
angular.module('core').controller('myController', ['$scope', 'FormService', function ($scope, FormService) {
FormService.getDropdownData(function (dropdownData) {
console.log(dropdownData); // Shows full object incl industries
console.log(dropdownData.industries); // object {}
});
} ]);
Given that your console log shows the correct object, that shows your service is functioning properly. Only one small mistake you have made here. You need to access the data attributes in your return promise.
angular.module('core').service('FormService', ['$http', function($http) {
var _this = this;
_this.dropdownData = {
contactTimes: ['Anytime','Morning','Afternoon','Evening'],
industries: {},
};
$http.get('/json').success(function(resp){
//note that this is resp.data.industries, NOT resp.industries
_this.dropdownData.industries = resp.data.industries;
});
}]);
Assuming that you're data is indeed existing and there are no problems with the server, there are quite a few possible solutions
Returning a promise
angular.module('core').service('FormService', ['$http', function($http) {
var _this = this;
_this.dropdownData = {
contactTimes: ['Anytime','Morning','Afternoon','Evening'],
industries: {},
};
_this.dropdownData.industries = $http.get('/json');
}]);
//Controller
FormService.industries
.then(function(res){
$scope.industries = res.industries
});
Resolving with routeProvider / ui-route
See: $http request before AngularJS app initialises?
You could also write a function to initialize the service when the application starts running. At the end of the day, it is about waiting for the data to be loaded by using a promise. If you never heard about promises before, inform yourself first.
The industries object will be populated at a later point in time when the $http call returns. In the meantime you can still bind to the reference in your view because you've preserved the reference using angular.copy. When the $http call returns, the view will automatically be updated.
It is also a good idea to allow users of your service to handle the event when the $http call returns. You can do this by saving the $promise object as a property of industries:
angular.module('core').service('FormService', ['$http', function($http) {
var _this = this;
_this.dropdownData = {
contactTimes: ['Anytime','Morning','Afternoon','Evening'],
industries: {},
};
_this.dropdownData.industries.$promise = $http.get('/json').then(function(resp){
// when the ansyc call returns, populate the object,
// but preserve the reference
angular.copy( resp.data.industries, _this.dropdownData.industries);
return _this.dropdownData.industries;
});
}]);
Controller
app.controller('ctrl', function($scope, FormService){
// you can bind this to the view, even though the $http call has not returned yet
// the view will update automatically since the reference was preserved
$scope.dropdownData = FormService.dropdownData;
// alternatively, you can hook into the $http call back through the $promise
FormService.dropdownData.industries.$promise.success(function(industries) {
console.log(industries);
});
});

Resources