How to correctly pass data from Service to Controller - javascript

I am trying to send data from my http service to my controller. The service correctly gets the data but it doesn't get sent to the controller.
Now, I am aware that the query is done asynchronously which is why I am trying to use $q.defer.
I tried following the example provided by a similar question : AngularJS $http call in a Service, return resolved data, not promises , however it still doesn't work.
Here is my Service :
.service("builds", ['$http', '$q', function($http, $q) {
var deferred = $q.defer();
$http({
method:'GET',
url: '/builds',
cache : true
}).success(function(data) {
deferred.resolve(data);
}).error(function(msg){
deferred.reject(msg);
});
console.log(deferred.promise);
return deferred.promise;}]);
And here is my routeProvider
$routeProvider.
when('/builds', {
controller: ['$scope', 'buildsData', function ($scope, buildsData) {
console.log("In routeprovider:" + buildsData);
$scope.allBuilds = buildsData;
}],
template: '<build-list></build-list>',
resolve: {
buildsData: ['builds', function(builds){
return builds;
}]
}
})
And finally here is a snippet of my Controller :
var app = angular.
module('buildList').
component('buildList', {
templateUrl: 'build-list/build-list.template.html',
controller: function BuildListController($scope, $window,$location,$cookies, builds) {
console.log($scope.allBuilds);
$scope.league = $scope.allBuilds;

As #vishal says
You should create a method in service because generally a service may have many get and set methods ( I mean best practice).
create a function say getData
function getData()
{
$http({
method:'GET',
url: '/builds',
cache : true
})
}
then you should be calling this method in controller
In the controller you should inject this service and then
builds.getData().then(function(s){
//result
},function(e){
//error
}
);

you shouldntt have
controller: ['$scope', 'buildsData', function ($scope, buildsData) {
console.log("In routeprovider:" + buildsData);
$scope.allBuilds = buildsData;
}],
and a controller in an other file:
You can directly do
when('/builds', {
controller: 'BuildListController'
template: '<build-list></build-list>',
resolve: {
buildsData: ['builds', function(builds){
return builds;
}]
}
})
and then in your controller
$scope.allBuilds = buildsData;
Beside, if you want add some functions to it , your service should look,like this:
.service("builds", ['$http', '$q', function($http, $q) {
var deferred = $q.defer();
getbuilds: function(){
$http({
method:'GET',
url: '/builds',
cache : true
}).success(function(data) {
deferred.resolve(data);
}).error(function(msg){
deferred.reject(msg);
});
console.log(deferred.promise);
return deferred.promise;}]);
}

Related

Angular 2/4 - Is it possible to initialize a provider only after a promise is resolved?

In my provider's constructor I have something like:
constructor(
public http: Http
) {
this.http.get("api.php").toPromise().then(res=>this.res = res.json());
}
However, I only want this provider to be accessible only after this.http.get("api.php").toPromise() is resolved. Everything else should be the same as a normal provider, such as the way it is injected. Is it possible? How?
What I did with AngularJS :
initialize you attribute with var = $q.defer()
when you meet the requested value, use var.resolve(value)
And until you get the value, you can postpone treatments using var.promise.then(function (data) { ... })
Whole code of a service :
angular.module('myApp')
.service('myService', ['$http', '$q', function ($http, $q) {
s.myVar = $q.defer();
s.loadMyVar = function () {
$http({
method: 'GET',
url: "somewhere"
}).then(function successCallback(response) {
s.myVar.resolve(response.data);
});
};
s.getMyVar = function () {
return s.myVar.promise.then(function (data) {
return data;
});
};
return s;
}]);

Call link function from controller Angularjs

I want to call a function declared inside the link function on my directive after an ajax request on my controller. So I want to communicate the controller with the link function.
This is my controller code:
.controller('productsCtrl', ['$scope', '$location', '$http', function ($scope, $location, $http) {
this.courseSeriesId = $location.search().courseSeriesId;
//FUNCTION: get data from products to show them
this.getCourseSeriesProducts = function(){
$http({
method: 'post',
url: "xxx",
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
data: {
functionName:'xxx',
courseSeriesId: this.courseSeriesId}
})
.success(function(response) {
---CODE
CALL welcome() function in LINK?
---CODE
}.bind(this))
.error(function(data){
alert('ERROR: ' + data);
});
}
And here is my directive code:
.directive('nlProducts', ['$location', function($location) {
return {
restrict: 'E',
templateUrl: function(elem, attr){
var type = '';
switch($location.search().courseSeriesId){
case 'en-efw':
type = 'tableview';break;
}
return 'xxx/nl-products-'+ type+'.php';
},
//control DOM elements
link:
function welcome() {
element.text('hi!');
}
};
}]);
I know that link is called after compilation, but in that moment the ajax request hasn't been finished yet. How can I do it?
Thanks.
You can't directly.
You can either use events with $broadcast in your controller and $on in your directive.
see this answer
or you can use $watch in your directive to look for a change in a variable your controller sets

How to make an AngularJS service that will retrieve data from Behance API?

I have been trying to create a AngularJS service that will get data from behance profiles.
I am injecting the $http and $q services to enable me to make requests to Behance API.
I am using a literal string for the url parameter for now to see how to resolve my issue. I will refactor my code to make it dynamic later.
behance.js File with the service relative to my Angular app.
'use strict';
angular
.module('angularPortfolioApp')
.factory('behanceUserData', ['$q', '$http',
function($q, $http) {
var service = {
getUser: function(username) { //ignore the parameter in this function I plan on implementing that after I have my question resolved.
var d = $q.defer();
$http({
method: 'JSONP',
url: 'https://www.behance.net/v2/users/USERNAME?api_key=XXX'
}).success(function(data) {
d.resolve(data);
}).error(function(reason) {
d.reject(reason);
});
return d.promise;
}
};
return service;
}
]);
app.js Declaring my Angular app with it's required dependencies.
'use strict';
angular.module('angularPortfolioApp', ['ngResource']);
In Chrome dev tools console I get an error of Uncaught SyntaxError: Unexpected token :
After doing some research I did find an article that stated that Angular does tack on a ":1" to the end of a JSONP request.
I am still having trouble understanding how I can get a successful request from an API especially from the behance API. I can still see the results in the web dev tools but since what ever I put into my .success block never runs I would appreciate some guidance.
The same code can also be seen in this plunker http://plnkr.co/edit/RZ42Y38BwKZBF2pGZJSR
I've updated your plunker.
You can use for getting any data from Behance API the following code:
angular.module('angularPortfolioApp', ['ngResource']);
angular
.module('angularPortfolioApp')
.factory('behanceUserData', ['$q', '$http',
function($q, $http) {
var service = {
getUser: function(username) {
var d = $q.defer();
$http({
method: 'GET',
url: 'https://www.behance.net/v2/users/USERNAME?api_key=XXX'
}).success(function(data) {
console.log(data);
d.resolve(data);
}).error(function(reason) {
console.log(reason);
d.reject(reason);
});
return d.promise;
}
};
return service;
}
])
.controller('MyController', function($scope, behanceUserData){
$scope.getUser = function(){
$scope.user = behanceUserData.getUser();
}
}
);
And in your view:
<div ng-controller="MyController">
<button ng-click="getUser()">Get</button>
<br/>
{{user | json}}
</div>
Plunker
But you should change this URL: 'https://www.behance.net/v2/users/USERNAME?api_key=XXX' because currently it not works.
I was able to get the data into my model by using the following factory.
.factory('behanceUserData', ['$q', '$http', 'BEHANCE_CLIENT_ID',
function($q, $http, BEHANCE_CLIENT_ID) {
return {
getUser: function(username) {
var q = $q.defer();
$http({
method: 'jsonp',
url: 'http://www.behance.net/v2/users/' + username,
params: {
client_id: BEHANCE_CLIENT_ID,
callback: 'JSON_CALLBACK'
}
}).success(function(data) {
console.log(data);
q.resolve(data);
});
return q.promise;
}
};
}
])

AngularJS $scope.foo is set with service, but later on in the same controller undefined

I have a service which calls API and gets json response. I inject this service into my controller and try to set $scope.tank variable with this received data. When I try to use this variable later on (in the same controller!) it is undefined. But the funny thing is that data is displayed in the front-end.
I've looked all over stackoverflow and I can not figure this out. I have created a plunker example - http://plnkr.co/edit/DkFNE8E9897dSF19eaU9?p=preview
My service:
appServices.service('TankService', function($q, $http) {
var data, deferred = $q.defer();
return {
init: function(id) {
var defer = $q.defer();
$http.get(options.api.base_url, { cache: 'true'})
.success(function(response) {
data = response;
deferred.resolve(data);
});
},
// return promise
getData: function() {
return deferred.promise;
}
};
});
I call my data in controller like this:
appControllers.controller('TankViewCtrl', ['$rootScope', '$scope', '$q', '$routeParams', '$location', '$sce', '$route', 'TankService',
function TankViewCtrl($rootScope, $scope, $q, $routeParams, $location, $sce, $route, TankService) {
var id = $routeParams.tank_id;
$scope.id = id;
$scope.tank = [];
// call our data
TankService.init(id);
TankService.getData().then(function(data){
$scope.tank = data;
});
// why is this undefined?
console.log($scope.tank);
}
]);
Thank in advance for your help!
HTTP calls are asynchronous requests.
You're asking your controller to display the result of the request without making sure you had an answer beforehand. That's why you get undefined.
Use :
TankService.getData().then(function(data){
$scope.tank = data;
console.log($scope.tank);
});

Best practice to set up a service or factory for $http contacting to REST API in AngularJS

I've created $http and REST API interface in AnguarJS service as a function that gets injected into different controllers like this:
// Global service to share between states
.service("appSharedService", ['$http', function($http) {
// Method: Returns list of all cities.
this.restCitiesGet = function() {
return $http.get('http://example/nkhorasaniec7/api/v0/city');
};
// Method:
this.citiesGet = function() {
this.restCitiesGet().success(function (data) {
console.log(data);
return data;
})
};
}])
console.log(data); returns the right json output when I call citiesGet() .
// Main controller that prints list of cities.
.controller('CityList', ['$scope', function($scope, appSharedService) {
$scope.cities = appSharedService.citiesGet();
console.log($scope.cities);
}]);
This is my controller injecting my service. console.log($scope.cities); here returns undefined.
$scope.cities value doesn't get changed after route calls this controller.
Is there something wrong with my setup?
Something interesting is that after I change route and come back to this controller again, this time $scope.cities have my REST data and everything's fine.
I think there's something wrong with timing or asynchronous functionality problem here that I'm not aware of.
EDIT:
I could have had $http in my controller and this works all well:
.controller('CityList', ['$scope', '$http', function($scope, $http, appSharedService) {
$http.get('http://localhost/nkhorasaniec7/api/v0/city').success(function (data) {
$scope.cities = data;
});
}]);
But I want to implement helper functions for this.
I would say that the common approach would be to return the promise directly to the controller, much like you have mentioned above by directly using the http request.
// Global service to share between states
.service("appSharedService", ['$http', function($http) {
// Method: Returning the promise
this.citiesGet = function() {
return $http.get('http://example/nkhorasaniec7/api/v0/city');
};
}])
Controller:
.controller('CityList', ['$scope', '$http', function($scope, $http, appSharedService) {
appSharedService.citiesGet().success(function (data) {
$scope.cities = data;
});
}]);
I think you are right about the timing issue. From what I understand, you are getting a promise, that at the moment you do console.log($scope.cities) is not yet resolved.
If you use $scope.cities inside your page, you should see the results as soon as they are loaded. Another option would be to use the promise then function if you really want to log.
$scope.cities = appSharedService.citiesGet().then(function(data) {
console.log(data);
return data;
};
Answering my own question:
I'm trying to make this happen in my a controller defined in my view using ng-controller, not a controller linked to a router (otherwise you could use resolve property like this Delaying AngularJS route change until model loaded to prevent flicker).
And I want to use REST using $http as a factory/service helper function for a cleaner code.
// Global service to share between states
.service("appSharedService", ['$http', '$q', function($http, $q) {
this.citiesGet = function() {
var deferred = $q.defer();
$http({method: 'GET', url: 'http://localhost/nkhorasaniec7/api/v0/city'}).success(function(data) {
deferred.resolve(data);
}).error(function(data, status) {
deferred.reject(data);
});
return deferred.promise;
};
}])
I used angular $q promise here.
// Our main controller that prints list of cities.
.controller('CityList', ['$scope', 'appSharedService', function($scope, appSharedService) {
var promise = appSharedService.citiesGet();
promise.then(
function(data){$scope.cities = data;}
,function(reason){alert('Failed: ' + reason);}
);
}])
And used then function to use that promise.
And now it always updates $scope.cities in any situation that template loads (not just in ng-view)
You can use $q service
.service("appSharedService", ['$http', '$q', function($http, $q) {
// Method: Returns list of all cities.
this.restCitiesGet = function() {
var deffered = $q.defer();
$http.get('http://example/nkhorasaniec7/api/v0/city').then(
//success
function(response){
deffered.resolve(response.data);},
//error
deffered.reject();
);
return deffered
};
and after that you can use promise in you controller
.controller('CityList', ['$scope', function($scope, appSharedService) {
$scope.cities = []
appSharedService.citiesGet().then(
//success
function(result){
angular.copy(result, $scope.cities)
console.log($scope.cities);
},
//error
function(){
console.log("load error");
});
}]);

Categories