I want to wait for a service $http result before the controller does the rest.
I tested some hardcoded JSON for myData and it IS visible in the controller, but as soon as I try to populate myData with a $http request, the controller is not waiting for it and just walks thru the rest of the code. The network tab from Chrome webdevelopper is showing the expected result for the request.
I already have the following:
var ListerApp = angular.module('ListerApp',[
'ListerAppFilters',
'sharedFactoryApp',
'sharedServiceApp',
'ListerAppController',
'infinite-scroll',
'angular-inview',
'ngRoute'
]);
ListerApp.config(['$routeProvider', '$httpProvider', function($routeProvider, $locationProvider) {
$routeProvider
.when('/list',
{
templateUrl: '/assets/services/partials/list.html',
controller: 'ListerCtrl',
resolve : {
'sharedServiceAppData': function($sharedServices){
// sharedFactoryAppData will also be injectable in your controller, if you don't want this you could create a new promise with the $q service
return $sharedServices.promise();
}
}
}
);
}]);
angular.module('sharedServiceApp', []).service('$sharedServices', ['$http', '$rootScope', '$q', function($http, $rootScope, $q) {
var myData = null;
return {
promise : function () {
if (!myData) {
$http({method : 'GET', url : '/shop/api/json', params : {
end : $rootScope.endmarkerSyncDataset,
page : 1,
per_page : $rootScope.itemsPerPage
}
}).success(function (data) {
myData = data.data_set;
//deferred.resolve(data.data_set);
});
// I allready tested this and this is OK: myData = {foo : 'bar'};
}
},
getShopData: function () {
return myData;
}
};
}]);
(function(){
var appController = angular.module('ListerAppController', []);
appController.controller('ListerCtrl', ['$scope', '$rootScope', '$http', '$filter', '$timeout', '$sharedFactories', '$sharedServices',
function($scope, $rootScope, $http, $filter, $timeout, $sharedFactories, $sharedServices) {
$scope.items = $sharedServices.getShopData();
console.log($scope.items); // return myData -> null
}
})();
I've done this a bunch of times here's what I usually do in my resolve object for the routeProvider, need to make sure you return all promises appropriately in order for the route change to wait on resolve properties.
$routeProvider
.when('/path',
{
templateUrl: 'some/path/to/template.html',
controller: 'myCtrl',
resolve : {
'myData': ['mySrvc',function(mySrvc){
return mySrvc.someMethod().then(function(response){
return response.data;
},function(){
return {};
});
}]
}
}
);
Then the service:
angular.module('myApp.services').factory('mySrvc',['$http',function($http){
var _url = 'https://someurl.com/path/to/api';
return {
someMethod : function(vars){
if(angular.isDefined(vars)){
return $http.post(_url,$.param(vars),{headers:{'Content-Type':'application/x-www.form-urlencoded'}});
}else{
return $http.get(_url);
}
}
};
}]);
Then in the controller you need to inject the resolve parameters at the end of the parameter list for the controller.
angular.module('myApp.controllers').controller('myCtrl',['$scope','myData',function($scope,myData){
});
In your code, in the resolve object of the routeProvider you have a return from a function that returns nothing, try returning the promise from the $http and then the data.data_set value in the success function of your service.
I have found something like $q.defer, resolve and promise.
It holds up everything until the status "promise" is reached.
Here's a link
angular.module('sharedServiceApp', []).service('$sharedServices', ['$http', '$rootScope', '$q', function($http, $rootScope, $q) {
var myData = null;
return {
promise : function () {
if (!myData) {
var deferred = $q.defer();
$http({method : 'GET', url : '/shop/api/json', params : {
end : $rootScope.endmarkerSyncDataset,
page : 1,
per_page : $rootScope.itemsPerPage
}
}).success(function (data) {
myData = data.data_set;
deferred.resolve(data.data_set);
}).error(function(data, status, headers, config) {
deferred.reject("Error: request returned status " + status);
});
return deferred.promise;
} else {
return myData;
}
},
getShopData: function () {
return myData;
},
setShopData: function (data) {
myData= data;
}
};
}]);
Related
LoginController.js
var MyApp = angular.module('MyApp', []);
MyApp.controller("LoginController",
["$scope", "$rootScope",
function ($scope , dataService) {
$scope.user = "sample";
$scope.checkUser = function () {
dataService.getUserData($scope.user).then(
function (results) {
$scope.userLoginInfo = results.userInfo;
},
function (results) {
$rootScope.showAlert(results, "There is a problem when trying to get user details.");
});
};
}]);
My DataService.js
MyApp.factory("dataService",
["$http", "$rootScope", "$q",
function ($http, $rootScope,$q) {
var dataService = {};
var getUserData = function (username) {
var promise = $http.get(baseUrl()+"/Controllers/UserDetails/?username=" + username)
.success(function (data, status, headers, config) {
return data;
})
.error(function (data, status, headers, config) {
return data;
});
return promise;
}
return {
getUserData: getUserData
}
}]);
i have included all .js files via bundleconfig .on calling dataService.getUserData in login controller , the described error occurs.
following is the stack trace
"TypeError: Object doesn't support property or method 'getUserData'\n at $scope.checkUser (http://localhost:58949/app/Controllers/LoginController.js:41:9)
at fn (Function code:2:195)\n at expensiveCheckFn (http://localhost:58949/Scripts/angular.js:16123:11)\n at callback (http://localhost:58949/Scripts/angular.js:26490:17)\n at Scope.prototype.$eval (http://localhost:58949/Scripts/angular.js:17913:9)\n at Scope.prototype.$apply (http://localhost:58949/Scripts/angular.js:18013:13)\n at Anonymous function (http://localhost:58949/Scripts/angular.js:26495:17)\n at n.event.dispatch (http://localhost:58949/Scripts/jquery-2.2.3.min.js:3:7481)\n at r.handle (http://localhost:58949/Scripts/jquery-2.2.3.min.js:3:5547)"
any help is greatly appreciated
You have not injected dataService so in your scenario instead of accessing "dataService" it is accesing "$rootScope"
try this :
// controller
var MyApp = angular.module('MyApp', []);
MyApp.controller("LoginController", ["$scope", "$rootScope", "dataService",
function($scope, $rootScope, dataService) {
$scope.user = "sample";
$scope.checkUser = function() {
dataService.getUserData($scope.user).then(
function(results) {
$scope.userLoginInfo = results.userInfo;
},
function(results) {
$rootScope.showAlert(results, "There is a problem when trying to get user details.");
});
};
}
]);
Also in your service
following line /Controllers/UserDetails/?username= seems to be incorrect, We pass query parameter in following way :
// "/Controllers/UserDetails?username="
// Service
MyApp.factory("dataService", ["$http", "$rootScope", "$q",
function($http, $rootScope, $q) {
var dataService = {};
var getUserData = function(username) {
var promise = $http.get(baseUrl() + "/Controllers/UserDetails?username=" + username)
.success(function(data, status, headers, config) {
return data;
})
.error(function(data, status, headers, config) {
return data;
});
return promise;
}
return {
getUserData: getUserData
}
}
]);
Inject the dataService.
MyApp.controller("LoginController",
["$scope", "$rootScope","dataService",
function ($scope ,rootScope dataService) {
. .
}
If the dataService not injected properly, hence it throws the error.
I try to use a service to get some data from server, but I had a problem: even the console log out the length when I print 'myData.length', when I try to find length of '$scope.test' controller variable it tell me that it is undefined.
What I should to do to use a $http service inside my own service?
app.controller('mainCtrl', ['$scope', 'mapServ',
function($scope, mapServ) {
$scope.test = [];
$scope.test = mapServ.test;
console.log('$scope.test = ' + $scope.test.length);
}]);
app.factory('mapServ', ['$http', function ($http) {
var path = "file path to my server data";
var out = {};
var myData = [];
out.test = $http.get(path).then(function (response) {
myData = response.data;
console.log(myData.length);
});
return out;
}]);
Take these service and controller as an example and you should follow John Papa's style guide while writing the code.
Service
(function() {
'use strict';
angular
.module('appName')
.factory('appAjaxSvc', appAjaxSvc);
appAjaxSvc.$inject = ['$http', '$q'];
/* #ngInject */
function appAjaxSvc($http, $q) {
return {
getData:function (path){
//Create a promise using promise library
var deferred = $q.defer();
$http({
method: 'GET',
url: "file path to my server data"
}).
success(function(data, status, headers,config){
deferred.resolve(data);
}).
error(function(data, status, headers,config){
deferred.reject(status);
});
return deferred.promise;
},
};
}
})();
Controller
(function() {
angular
.module('appName')
.controller('appCtrl', appCtrl);
appCtrl.$inject = ['$scope', '$stateParams', 'appAjaxSvc'];
/* #ngInject */
function appCtrl($scope, $stateParams, appAjaxSvc) {
var vm = this;
vm.title = 'appCtrl';
activate();
////////////////
function activate() {
appAjaxSvc.getData().then(function(response) {
//do something
}, function(error) {
alert(error)
});
}
}
})();
In your code you do not wait that $http has finished.
$http is an asynchronous call
You should do it like this
app.controller('mainCtrl', ['$scope', 'mapServ',
function($scope, mapServ) {
$scope.test = [];
$scope.test = mapServ.test.then(function(response) {
console.log(response.data);
}, function(error) {
//handle error
});;
}
]);
app.factory('mapServ', ['$http', function($http) {
var path = "file path to my server data";
var out = {};
var myData = [];
out.test = $http.get(path);
return out;
}]);
$http call that you are making from factory is asynchronous so it will not wait , until response come, it will move on to the next execution of the script, that is the problem only try Weedoze's asnwer, it is correct way to do this.
I'm trying to get a value from a URL part, into my $http getURL request. I have tried a few solutions (such as HTML5mode) but have not had success.
Here is my code:
angular.module('myapp123.products', [])
.factory('productsApi', ['$http', '$location',
function($http, $location){
var BASE_URL = 'http://stashdapp-t51va1o0.cloudapp.net/api/item/';
return {
get: getApiData
};
function getData() {
var product_id = $location.path().split("/")[3] || "Unknown"; //URL = /#/product/id/1234 <---
return $http.get(BASE_URL + product_id);
}
}]
)
.controller('productsCtrl', ['$scope', '$log', 'productsApi', 'UserService',
function($scope, $log, productsApi, UserService) {
$scope.isVisible = function(name){
return true;// return false to hide this artist's albums
};
// <====== Rewrite with accounts preferences
productsApi.getApiData()
.then(function (result) {
//console.log(JSON.stringify(result.data)) //Shows log of API incoming
$scope.products = result.data;
})
.catch(function (err) {
$log.error(err);
});
}
]);
The code in your example has a lot of syntax errors in it. Here is what it should look like, based on what I think you are going for...
angular.module('myapp123.products', [])
.config(locationConfig)
.factory('productsApi', productsApiFactory)
;
locationConfig.$inject = ['$locationProvider'];
function locationConfig($locationProvider) {
$locationProvider.html5Mode(true);
}
productsApiFactory.$inject = ['$http', '$location'];
function productsApiFactory($http, $location) {
var BASE_URL = 'http://stashdapp-t51va1o0.cloudapp.net/api/list/';
return {
get: getData
};
function getData() {
var product_id = $location.path().split("/")[3] || "Unknown";
return $http.get(BASE_URL + product_id);
}
}
In this version, the config function is correctly defined to set up html5mode and the service factory is configured to use $location each time the get() method is called.
You would use the service in a controller like this:
ExampleController.$inject = ['productsApi'];
function ExampleController(productsApi) {
productsApi.get()
.then(function onSuccess(res) {
// handle successful API call
})
.catch(function onError(err) {
// handle failed API call
})
;
}
I am trying to create a service to get json and pass it to me homeCtrl I can get the data but when a pass it to my homeCtrl it always returns undefined. Im stuck.
My Service:
var myService = angular.module("xo").factory("myService", ['$http', function($http){
return{
getResponders: (function(response){
$http.get('myUrl').then(function(response){
console.log("coming from servicejs", response.data);
});
})()
};
return myService;
}
]);
My Home Controller:
var homeCtrl = angular.module("xo").controller("homeCtrl", ["$rootScope", "$scope", "$http", "myService",
function ($rootScope, $scope, $http, myService) {
$scope.goData = function(){
$scope.gotData = myService.getResponders;
};
console.log("my service is running", $scope.goData, myService);
}]);
You should return promise from getResponders function, & when it gets resolved it should return response.data from that function.
Factory
var myService = angular.module("xo").factory("myService", ['$http', function($http) {
return {
getResponders: function() {
return $http.get('myUrl')
.then(function(response) {
console.log("coming from servicejs", response.data);
//return data when promise resolved
//that would help you to continue promise chain.
return response.data;
});
}
};
}]);
Also inside your controller you should call the factory function and use .then function to get call it when the getResponders service function resolves the $http.get call and assign the data to $scope.gotData
Code
$scope.goData = function(){
myService.getResponders.then(function(data){
$scope.gotData = data;
});
};
This is an example how I did for my project, it work fine for me
var biblionum = angular.module('biblioApp', []);//your app
biblionum.service('CategorieService', function($http) {
this.getAll = function() {
return $http({
method: 'GET',
url: 'ouvrage?action=getcategorie',
// pass in data as strings
headers: {'Content-Type': 'application/x-www-form-urlencoded'} // set the headers so angular passing info as form data (not request payload)
})
.then(function(data) {
return data;
})
}
});
biblionum.controller('libraryController', function($scope,CategorieService) {
var cat = CategorieService.getAll();
cat.then(function(data) {
$scope.categories = data.data;//don't forget "this" in the service
})
});
Trying to return data from the factory and logging within the factory outputs the correct data, but once passed to the controller it is always undefined. If I have my factory logic inside the controller it will work fine. So it must be something simple Im missing here?
Application
var app = angular.module('app', []);
app.controller('animalController', ['$log', '$scope', 'animalResource', function($log, $scope, animalResource) {
$scope.list = function() {
$scope.list = 'List Animals';
$scope.animals = animalResource.get(); // returns undefined data
$log.info($scope.animals);
};
$scope.show = function() {};
$scope.create = function() {};
$scope.update = function() {};
$scope.destroy = function() {};
}]);
app.factory('animalResource', ['$http', '$log', function($http, $log) {
return {
get: function() {
$http({method: 'GET', url: '/clusters/xhrGetAnimals'}).
success(function(data, status, headers, config) {
//$log.info(data, status, headers, config); // return correct data
return data;
}).
error(function(data, status, headers, config) {
$log.info(data, status, headers, config);
});
},
post: function() {},
put: function() {},
delete: function() {}
};
}]);
Log Info
[Object, Object, Object, Object, Object, Object, Object, Object, Object, Object]
200 function (name) {
if (!headersObj) headersObj = parseHeaders(headers);
if (name) {
return headersObj[lowercase(name)] || null;
}
return headersObj;
} Object {method: "GET", url: "/clusters/xhrGetAnimals"}
Your get() method in service is not returning anything. The return inside the success callback only returns from that particular function.
return the $http object
Che this example that is how you use the promises and you return the factory then you access the methods injecting the service on your controller
Use dot syntax to access the function you define on the service
'use strict';
var app;
app = angular.module('app.formCreator.services', []);
app.factory('formCreatorService', [
'$http', '$q', function($http, $q) {
var apiCall, bjectArrarContainer, deferred, factory, webBaseUrl, _getFormElementsData;
factory = {};
deferred = $q.defer();
bjectArrarContainer = [];
webBaseUrl = 'https://tools.XXXX_url_XXXXX.com/XXXXXXX/';
apiCall = 'api/XXXXX_url_XXXX/1000';
_getFormElementsData = function() {
$http.get(webBaseUrl + apiCall).success(function(formElements) {
deferred.resolve(formElements);
}).error(function(err) {
deferred.reject(error);
});
return deferred.promise;
};
factory.getFormElementsData = _getFormElementsData;
return factory;
}
]);
then do it like this for example
'use strict';
var app;
app = angular.module('app.formCreator.ctrls', []);
app.controller('formCreatorController', [
'formCreatorService', '$scope', function(formCreatorService, $scope) {
$scope.formElementsData = {};
formCreatorService.getFormElementsData().then(function(response) {
return $scope.formElementsData = response;
});
}
]);