I have a service that retrieves data via REST. I want to store the resulting data in service level variable for use in multiple controllers. When I put all the REST logic directly into controllers everything works fine but when I attempt to move the retrieval / storing of data into a service the controller is not being updated when the data comes back. I've tried lots of different ways of maintain the binding between service and controller.
Controller:
myApp.controller('SiteConfigCtrl', ['$scope', '$rootScope', '$route', 'SiteConfigService',
function ($scope, $rootScope, $route, SiteConfigService) {
$scope.init = function() {
console.log("SiteConfigCtrl init");
$scope.site = SiteConfigService.getConfig();
}
}
]);
Service:
myApp.factory('SiteConfigService', ['$http', '$rootScope', '$timeout', 'RESTService',
function ($http, $rootScope, $timeout, RESTService) {
var siteConfig = {} ;
RESTService.get("https://domain/incentiveconfig", function(data) {
siteConfig = data;
});
return {
getConfig:function () {
console.debug("SiteConfigService getConfig:");
console.debug(siteConfig);
return siteConfig;
}
};
}
]);
View:
<div class="span4" ng-controller="SiteConfigCtrl">
<header>
<h2>
{{site.title}}
</h2>
</header>
I would write it with promise factory:
myApp.factory('SiteConfigService', ['$http', '$rootScope', '$timeout', 'RESTService', '$q'
function ($http, $rootScope, $timeout, RESTService, $q) {
var siteConfig = {} ;
RESTService.get("https://domain/incentiveconfig", function(data) {
siteConfig = data;
});
// or just
// var siteConfig = RESTService.get("https://domain/incentiveconfig");
return {
getConfig:function () {
var deferred = $q.defer();
deferred.resolve(siteConfig);
return deferred.promise;
}
};
}
]);
Controller side
SiteConfigService.getConfig()
.then(function (result) {
$scope.site = result;
}, function (result) {
alert("Error: No data returned");
});
Solution based on Maxim's answer above - JsFiddle - http://jsfiddle.net/acb98sm/2pQ6A/6/
var myApp = angular.module('myApp',[]);
myApp.controller('SiteConfigCtrl', ['$scope', '$rootScope', '$route', 'SiteConfigService',
function ($scope, $rootScope, $route, SiteConfigService) {
SiteConfigService.getConfig()
.then(function (result) {
console.log("results are in ");
console.log(result);
$scope.site = result.data;
}, function (result) {
alert("Error: No data returned");
});
}
]);
myApp.factory('SiteConfigService', ['$http', '$rootScope', '$timeout', 'RESTService', '$q',
function ($http, $rootScope, $timeout, RESTService, $q) {
var siteConfigFn = RESTService.get("http://graph.facebook.com/616366118/", function(data) {
console.log("SiteConfigService returns");
});
return {
getConfig:function () {
var deferred = $q.defer();
deferred.resolve(siteConfigFn);
return deferred.promise;
}
};
}
]);
myApp.$inject = ['$scope', 'SiteConfigService', 'RESTService'];
myApp.factory('RESTService',
function ($http) {
return {
get:function (url, callback) {
return $http.get(url, {withCredentials:false}).
success(function (data, status, headers, config) {
callback(data);
}).
error(function (data, status, headers, config) {
console.log("failed to retrieve data");
});
},
post:function (url, data, callback) {
return $http.post(url, data, {withCredentials:true}).
success(function (data, status, headers, config) {
callback(data);
}).
error(function (data, status, headers, config) {
console.log("failed to retrieve 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 have this service to retrieve a list of cars from a WebAPI server :
angular.module('MyServices')
.service('carService', ['$http', '$rootScope',
function ($http, $rootScope) {
this.getList =function(userName, ticket)
{
$rootScope.$emit('My.OnBusy');
$http.get('api/car'
, { params: {userName: userName} }
).success(function (data) {
$rootScope.$emit('My.OnIdle');
if (data[0] && data[0].Name == "Error")
{
$rootScope.$emit("My.OnError", data[0].Model);
return {};
}
return data;
}).error(function (data, status, headers, config) {
$rootScope.$emit('My.OnIdle');
$rootScope.$emit("My.OnError", "Error in communication with server.");
return {};
});
}
}]
);
And in the controller I use it like this :
angular.module('MyControllers')
.controller('carController', function CarController($rootScope, $scope, $http, carService) {
$scope.loadCars = function (userName, ticket) {
$scope.Cars = carService.getList(userName, ticket);
}
$scope.loadCars($rootScope.user.email, '');
});
But the $scope.Cars is Undefined after the cal to getList. I tried to use "then" when I call the service but it was unsuccessful.
Saying that I want to handle success and error of the operation in the service itself, how can I get final result in the controller?
For future reference :
Service should be like this :
angular.module('MyServices')
.service('carService', ['$http', '$rootScope', '$q'
function ($http, $rootScope, $q) {
this.getList =function(userName, ticket)
{
$rootScope.$emit('My.OnBusy');
var deferred = $q.defer();
$http.get('api/car'
, { params: {userName: userName} }
).success(function (data) {
$rootScope.$emit('My.OnIdle');
if (data[0] && data[0].Name == "Error")
{
$rootScope.$emit("My.OnError", data[0].Model);
deferred.reject(data[0].Address);
//return {};
}
deferred.resolve(data);
//return data;
}).error(function (data, status, headers, config) {
$rootScope.$emit('My.OnIdle');
$rootScope.$emit("My.OnError", "Error in communication with server.");
deferred.reject("Error in communication with server.");
//return {};
});
return deferred.promise;
}
}]
);
And now "then" works in the controller :
angular.module('MyControllers')
.controller('carController', function CarController($rootScope, $scope, $http, carService) {
$scope.loadCars = function (userName, ticket) {
carService.getList(userName, ticket).then(function (data) {
$scope.Cars = data;
});;
}
$scope.loadCars($rootScope.user.email, '');
});
I have this code where two controllers are using a shared service to communicate.
var app = angular.module('AdminApp', ['ngRoute']);
app.factory('SharedService', function ($rootScope) {
var sharedService = {
userId: [],
BroadcastUserId: function (id) {
this.userId.push(id);
$rootScope.$broadcast('handleBroadcast');
}
};
return sharedService;
});
app.config(function ($routeProvider) {
$routeProvider.when('/login', {
templateUrl: "adminLogin.html"
});
$routeProvider.when('/main', {
templateUrl: 'adminMain.html'
});
$routeProvider.otherwise({
redirectTo: '/login'
});
});
app.controller('authCtrl', function ($scope, $http, $location, SharedService) {
$scope.Userid = '';
$scope.authenticate = function (user, pass) {
$http.post('http://localhost/NancyAPI/auth', {
UserName: user,
Password: pass
}).success(function (data) {
$scope.$broadcast('Token', data.Token);
$http.defaults.headers.common['Authorization'] = 'Token ' + data.Token;
$scope.Userid = data.UserId;
SharedService.BroadcastUserId($scope.Userid);
$location.path("/main");
}).error(function (response) {
$scope.authenticationError = response.error || response;
});
};
$scope.$on('handleBroadcast', function () {
console.log('on');
});
}).$inject = ['$scope', '$rootScope', 'SharedService'];
app.controller('mainCtrl', function ($scope, $http, $q, SharedService) {
$scope.tests = [];
$scope.userId = -1;
$scope.getTests = function () {
var deferred = $q.defer();
$http.get('http://localhost/NancyAPI/auth/tests/' + $scope.userId).
success(function (data) {
deferred.resolve(data);
$scope.tests = angular.fromJson(data);
}).error(function (response) {
});
};
// THIS IS NOT FIRING
$scope.$on('handleBroadcast', function () {
$scope.userId = SharedService.userId;
});
}).$inject = ['$scope', '$rootScope', 'SharedService'];
For some reason the $scope.$on is firing in the AuthCtrl controller but not in the mainCtrl.
// THIS IS NOT FIRING
$scope.$on('handleBroadcast', function () {
$scope.userId = SharedService.userId;
});
Why is this happening and how do I fix it?
I made a subtle mistake of not providing the {$rootScope} as dependency. Once I corrected that, it worked for me. I used Inline Array Annotation mechanism to achieve the same.
I am new to AngularJS and having an strange problem, that I can't access to $scope.name. In the factory DataService I have a method getData() which uses $http.get(...).
angular.module("app", []).factory("DataService", function($q, $http) {
var service = {};
service.getData = function() {
var deferred = $q.defer();
$http.get(apiPath).success(function(data) {
deferred.resolve(data);
}).error(function(data, status) {
deferred.reject('Error: ' + status);
});
return deferred.promise;
};
return service;
}).controller("DataController", ["$scope", "DataService", function($scope, DataService) {
$scope.datas = [];
DataService.getData().then(function(data){
$scope.datas = data;
}, function(error) {
console.log(error);
});
console.log($scope.datas); // it returns []
}]);
I can't understand why it returns an empty array.
I am trying to retrieve the "cart" in the following way Factory->Service->Controller.
I am making an $http call but it is returning an object. If I debug I can see that the request is made and is retrieving the data (in the network section of the debugger).
angular.module('companyServices', [])
.factory('CompanyFactory', ['$http', function($http){
return {
getCart: function(cartId) {
var promise = $http.get('company/Compare.json', {params: {'wsid': cartId}})
success(function(data, status, headers, config) {
return data;
}).
error(function(data, status, headers, config) {
return "error: " + status;
});
}
};
}]);
angular.module('itemsServices', [])
.service('ItemsServices', ['CompanyFactory', function(CompanyFactory){
var cartId = new Object();
this.getCartId = function(){
return cartId;
};
this.cartId = function(value){
cartId = value;
};
this.getCart = function(){
return CompanyFactory.getCart(this.getCartId()).then(function(data){return data});
};
};
.controller('CompareItemsCtrl', ['$scope', '$location', 'ItemsServices', function($scope, $location, ItemsServices){
var params = $location.search().wsid;
ItemsServices.cartId(params);
console.log('ItemsServices.getCart()');
console.log(ItemsServices.getCart());
};
Thank you
Since $http returns a promise, I think you would be better of passing in your success and error functions to getCart()
.controller('CompareItemsCtrl', ['$scope', '$location', 'ItemsServices', function($scope, $location, ItemsServices){
var params = $location.search().wsid;
ItemsServices.cartId(params);
console.log('ItemsServices.getCart()');
console.log(ItemsServices.getCart());
ItemsService.getCart().then(function(response){
console.log('success');
},function(response){
console.log('error');
});
};