Sharing ajax data between multiple controllers in angular using service - angularjs

Hi I have two controllers
pqsAppModule.controller('NotificationBoxController',function($scope,items) {
$scope.list = items.list();
})
and
pqsAppModule.controller('NotificationController',function($scope,items) {
$scope.list = items.list();
})
I need to create an "items" service that would do an ajax request and return data for any controller which would have it injected. And I want, that the query will be done only once, and items will be shared between all controllers.
pqsAppModule.factory('items', function($http) {
var items = [];
var itemsService = {};
$http.get('api/notification').then(function(response){
items = response.data;
});
itemsService.list = function() {
return items;
};
return itemsService;
});
But I don't understand why angular makes the request, and receives data, but all items in controllers are empty.

It happens because the factory should be defined by different way.
(I took dummy URL only to load data by async way)
HTML
<div ng-controller="NotificationBoxController">
<button ng-click="showMe();">press me</button>
<pre>NotificationBoxController: {{items.getList()|json}}</pre>
</div>
<div ng-controller="NotificationController">
<pre>NotificationController: {{items.getList()|json}}</pre>
</div>
JS
var pqsAppModule = angular.module('myApp', []);
pqsAppModule.controller('NotificationBoxController',function($scope,items) {
$scope.items = items;
$scope.showMe= function(){
items.query();
}
});
pqsAppModule.controller('NotificationController',function($scope,items) {
$scope.items = items;
});
pqsAppModule.factory('items', function ($http) {
var current = {};
var address = 'Singapore, SG, Singapore, 153 Bukit Batok Street 1';
var URL = 'http://maps.googleapis.com/maps/api/geocode/json?address=' + address + '&sensor=true';
var factory = {
query: function () {
var data = $http({method: 'GET', url:URL}).then(function (result) {
current = result.data.results[0];
}, function (result) {
alert("Error: No data returned");
});
},
getList: function () {
return current;
}
}
return factory;
});
Demo Fiddle
From this example we call items.getList() from HTML for both controllers. But if we want to update the model through the controller, we need a listener like $watch

Try this
$http.get('api/notification').then(function(response){
angular.foreach(response.data,function(item) {
items.push(item);
});
});
Basically do not create a new array but fill the existing one.

Related

Updating array after $http request not working

ng-repeat in md-sidenav
<md-list>
<md-list-item ng-repeat="it in cars">
{{ it.name }}
</md-list-item>
</mdlist>
Car Controller
self.refreshUI = function(select) {
carService.getAllCars()
.then(function (res) {
$scope.cars = carService.carsList;
console.log($scope.cars);
}, function (err) {
//error
})
};
// Load all registered cars
self.refreshUI(null);
Above code runs when controller is loaded (last line) and it's working fine. But when I create new car (cars are stored in mysql db) and I want to update $scope.cars array by self.refreshUI() function it will not work until refreshing page mannualy.
console.log($scope.cars) from refreshUI function returns correct result but console.log(angular.element($0).scope().cars) gives wrong array (without new cars)
Car Service
function carService($q, $http) {
var cars = this;
cars.carsList = {};
cars.getAllCars = function() {
var defer = $q.defer();
$http.get("http://car.app/getCars")
.success(function(res) {
cars.carsList = res;
defer.resolve(res);
})
.error(function(err, status){
defer.reject(err);
});
return defer.promise;
};
return cars;
}
Where could be the problem?
//edit: $rootScope is working fine but i still want to use $scope
Why aren't you using a returned Promise as a result from the $http call? Besides of a better code style, it could solve your problem. With that kind of service-controller infrastructure I never had 'binding problems' like that.
function carService($q, $http) {
var cars = this;
cars.carsList = {};
cars.getAllCars = function() {
return $http.get('http://car.app/getCars').then(function (response) {
cars.carsList = response.data;
return response.data;
});
};
return cars;
}
In your controller you could then do something like that:
self.refreshUI = function() {
carService.getAllCars()
.then(function (data) {
// just obtain the promise data
$scope.cars = data;
}, function (err) {
// error handling
});
};
self.refreshUI();

Angular : Share data returned from factory between controllers

I havea factory call HTTP end point to fetch user:
.factory('me', function($resource, VAS_API_URL, $q) {
return {
getUser: function() {
var deferred = $q.defer();
var url = VAS_API_URL + 'api/me';
$resource(url)
.get(function(user) {
deferred.resolve(user);
}, function(response) {
deferred.reject(response);
});
return deferred.promise;
}
};
})
I use this factory in many controllers and, i bind the data to the DOM successfully, but at times i want to use the data returned from the factory in my controller like to save the user name with a notification so i had to do the following:
.controller('createNotificationCtrl', function($scope, VAS_API_URL, me) {
var Burl = VAS_API_URL + 'api/notification';
$scope.profile = me.getUser();
$scope.profile.then(
function(user) {
$scope.owner = user;
$scope.item = {};
$scope.item.message = $scope.message;
$scope.item.owner = $scope.owner.displayName;
},
function(response) {
console.log(response);
}
);
})
I had to creat $scope.item = {}; in the factory call so i could get the displayName then send the object to save a notification but what if i want to save also another filed from another factory. How it could be done?
The factory should create the object and hold it as a state.
The controller's should use the reference from the factory and update it for everyone.
factory code sample:
this.stateObj = {};
....
....
this.getUser = function(){
var promise = $http.get(url);
promise.then(function(res){
// update stateObj
});
return promise;
}
ctrl code sample:
factory.getUser().then(function(res){
$scope.stateObj = factory.getStateObj();
});

angularJS service not getting called

I'm very new to AngilarJS. I am trying to write a service in angularJS.
<script>
var module = angular.module("myapp", []);
module.service('BrandService', function ($http) {
var brands = [];
this.getBrands = function()
{
return $http.get('http://admin.localhost/cgi-bin/brand.pl')
.then(function(response)
{
brands = response.brands;
alert (brands);
});
}
//simply returns the brands list
this.list = function ()
{
return brands;
}
});
module.controller("brandsController", function($scope, BrandService) {
$scope.brandlist = BrandService.list();
alert ($scope.brandlist);
});
</script>
The statement "alert (brands);" is not getting called. What is the issue with this code. Is m missing any thing in implementation?
$http calls are always async. Meaning, even you do a .then at your service, there is no way it will properly the resolved data back into your controller. You will have to write it in your controller.
Your Service:
module.service('BrandService', function($http) {
var brands = [];
this.getBrands = function() {
//do not need the dot then.
return $http.get('http://admin.localhost/cgi-bin/brand.pl')
}
//simply returns the brands list
this.list = function() {
return brands;
}
});
In your controller:
module.controller("brandsController", function($scope, BrandService) {
BrandService.list()
.then(function(response) {
$scope.brandlist = response.brands;
alert($scope.brandlist);
});
});
In service:
this.getBrands = function() {
$http.get('http://admin.localhost/cgi-bin/brand.pl').then(function(response) {
brands = response.brands;
alert(brands);
return brands;
});
}
In controller:
$scope.brandlist = BrandService.getBrands();
alert($scope.brandlist);

Angularjs; use $http in service returns reference instead of actual data

I'm using the services directive in Angularjs not factory and I need to populate a json file to local variable;
/* Contains projects on the town */
leMaireServicess.service('cityService', function($http) {
// JSON regions and cities loader
this.cities = [];
// initCities
this.initCities = function() {
this.cities = $http.get('data/census/cities.js').success(function(data) {
return data;
});
return this.cities;
};
// Get city info
this.getCity = function() {
return this.cities;
};
});
And in my controller I have
// Saved game controller
leMaireControllers.controller('GameCoreCtrl', function($scope, cityService) {
/* Control the town project slides */
cityService.initCities();
$scope.city = cityService.getCity();
console.log($scope.city);
});
But instead of returning the actual data, it returns;
Object {then: function, catch: function, finally: function, success: function, error: function}
You can use a watch to make this work (see plunker)
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope,cityService) {
//$scope.cities = [];
$scope.service = cityService;
cityService.initCities();
$scope.$watch('service.getCity()', function(newVal) {
$scope.cities = newVal;
console.log(newVal)
});
});
app.service('cityService', function($http) {
var that = this;
this.cities = [];
this.initCities = function() {
$http.get('data.js').success(function(data) {
that.cities = data.cities;
});
};
this.getCity = function() {
return this.cities;
};
});
$http returns a promise which is what you're setting this.cities to.
This might help explain more,
https://stackoverflow.com/a/12513509/89702
In your controller you should be able to do something like this...
cityService.initCity().then(function(data) { $scope.city = data; }
You are working with promises which represent the result of an action that is performed asynchronously. Try it this way:
leMaireServicess.service('cityService', function($http) {
this.promise = {};
// initCities
this.initCities = function() {
this.promise = $http.get('data/census/cities.js');
};
// Get city info
this.getCity = function() {
return this.promise;
};
});
And in the controller you need to put your code in a callback:
// Saved game controller
leMaireControllers.controller('GameCoreCtrl', function($scope, cityService) {
/* Control the town project slides */
cityService.initCities();
cityService.getCity().then(function(result){
$scope.city = result.data;
console.log($scope.city);
});
});

AngularJS $q.all for all queries in controller

I have multiple queries in one controller, that load while the controller is loading (and after I click on some elements)
var d = $q.defer();
$scope.userOrders = UserOrders.query({id:$routeParams.id}, function(result) {
d.resolve(result);
});
$q.all([d.promise]).then(function(response){
$('#loading').hide();
});
How i can write this only once, not in each controller?
Encapsulate your ajax logic in a service
var services = angular.module('myServices', []);
services.factory('AjaxLoader', ['$q', function($q) {
return {
doAjax : function() {
var d = $q.defer();
$scope.userOrders = UserOrders.query({id:$routeParams.id}, function(result) {
d.resolve(result);
});
$q.all([d.promise]);
}
}
});
In your controller.
var controllers = angular.module('myControllers',[]);
controllers.controller('Controller', ['AjaxLoader', function(AjaxLoader) {
AjaxLoader.doAjax().then(function() {
$("#loading").hide();
});
}]);

Resources