How broadcast data of HTTP post method in angularjs - angularjs

I'm using the same HTTP method in different controller like following sample:
Service:
var method="sampleMethod"
HotalStatisticService.GetReservations = function (data) {
return $http({
method: 'POST',
data: data,
cache: false,
url:'http://sample.com/'+method
});
}
first controller
.controller("SampleACtrl", function ($scope,HotalStatisticService ) {
HotalStatisticService.GetReservations({start:start, end:end, type:type})
.success(function (data) {
$scope.sampleA=data;
})
}
second controller
.controller("SampleBCtrl", function ($scope,HotalStatisticService ) {
HotalStatisticService.GetReservations({start:start, end:end, type:type})
.success(function (data) {
$scope.sampleB=data;
})
}
How do I use here method in the only one controller?

Let me say that the other solution that uses factories is probably a MUCH better solution.Using Services is also a good option.
Another ,perhaps crude way to do it is using $rootScope.Answer below.
What you essentially want to do is share data between the two controllers. Based on your reply from the comments, both the controllers belong to the same module.You can use $rootScope here to act as a common point.
As you can see, i've added $rootScope as a dependency in both the controllers and simply printed the txt variable in the second div.
JS Code
var app = angular.module('plunker', []);
app.controller('ACtrl', function($scope,$rootScope) {
$scope.name = 'This is Controller A ';
$scope.execute = function() {
alert('Executed!');
}
$rootScope.txt="Hi there from the other side";
});
app.controller('BCtrl', function($scope,$rootScope) {
$scope.name = 'This is Controller B ';
});
HTML
<div ng-controller="ACtrl">
<p>Hello {{name}}!</p>
</div>
<div ng-controller="BCtrl">
<p>Hello {{name}}!</p>
{{txt}}
</div>
Here is the DEMO

What I'd do is create a factory service that handles your HTTP requests, and then inject that service into your controllers... Code would look something like this:
var app = angular.module('sampleApp');
app.factory('sampleFactory', ['$http',
function($http) {
return {
getData: function(success, fail) {
if (_dataStore) {
success(_dataStore);
}
$http({
//fill in your params here
})
.then(
function successCallback(response) {
//store data in the _dataStore object
success(response)
}, fail(response))
},
_dataStore: {}
}
}
]);
app.controller('SampleACtrl', ['$scope', 'sampleFactory',
function($scope, sampleFactory) {
$scope.sampleA = sampleFactory.getData(success, fail);
}
]);
app.controller('SampleBCtrl', ['$scope', 'sampleFactory',
function($scope, sampleFactory) {
$scope.sampleB = sampleFactory.getData(success, fail);
}
]);
The main idea behind doing it like this is that you only make the HTTP request once, and then store the data in the factory as an object. When you call the getData() function on that object, you'll either get what is actually in the factory already (meaning the request was already made) or you'll go make the request. You'd pass in 2 functions (success or fail) as your response functions to the $http call. This is by far not 100% good, there's many improvements(add $q in there to return promises, etc) but it's a start in the right direction.
Long story short: USE FACTORIES!

Related

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>

AngularJs, calling a $resource from within an Interceptor

I have just about given up with this. But I have a $resource that uses a query() to retrieve a list of items. I then have an Interceptor that runs over those items in order to insert an $interval.
The $interval at a specific point will then get an item again using the $resource's get() function. But its this get() that is not working.
The call happens but I cannot get the response back into the template.
myServices.factory('Items', ['$resource',
function($resource) {
return $resource("/items", {}, {
'query': {
interceptor: MyInterceptor,
url: "/items",
isArray: true
},
})
}]);
myServices.factory('MyInterceptor', function($q, $interval, $injector, $rootScope) {
return {
'response': function(response) {
angular.forEach(response.resource, function (item) {
$interval(function () {
item.something = 1 + item.something;
if(item.something == 10)
{
item = $injector.get("Mine").get({slug: item.id});
}
});
});
return response;
}
};
});
I thought that this line item = $injector.get("Mine").get({slug: item.id}); would work, but it doesn't. The new item is not changed in the template.
So I changed it to something like this, which did not work either;
$injector.get("Mine").get({slug: item.id}, function(data){
item = data;
});
I have tried with $q and $promise too, but I had no luck with those either. Finding decent examples on those subjects was tough too.
In short ...... I am using an Interceptor inside a $resource, with an $interval which then needs to eventually change a single value within an array of values within the $scope - how can I get this to work?
In short ...... I am using an Interceptor inside a $resource, with an $interval which then needs to eventually change a single value within an array of values within the $scope - how can I get this to work?
Based on the above statement I will give an answer.
First things first, remove the interceptor. You won't need it. Instead use a service.
Write a service called ProcessedItems.
angular.module('app')
.service('ProcessedItems', ['Items', '$q', function(Items, $q){
return {
query: function() {
var defer = $q.defer();
Items.query()
.$promise
.then(function(response){
angular.forEach(response.resource, function(i)){
i.s = 1 + i.s;
if(i.s == 10) {
i = $injector.get("Mine").get({slug: i.id});
i.$promise.then(function(){
defer.resolve(response);
}, function(){
defer.reject();
});
};
};
});
return defer.promise;
}
};
}]);
After this service is set up, in your controller you can do
angular.module('app')
.controller('AppController', ['$scope', 'ProcessedItems',
function($scope, ProcessedItems){
$scope.items = [];
ProcessedItems.query().then(function(pitems){
$scope.items = pitems;
});
});
What this will essentially do is first process the data completely and then display it in the view.

How get access to global variable from Factory Angular JS?

I tried to write factory method in Angular JS:
.factory('FriendsFactory', function(){
var friend = {};
friend.delete = function(id) {
notificationsModal.show('danger', messages_info[86]);
notificationsModal.confirm(function() {
this.deleteAjax(event, id, type);
})
}
friend.deleteAjax = function (event, id, type){
var target = angular.element(event.target);
var request = $http({
method: "POST",
url: "/subscribe/deletesubscriber",
data: $.param({ id : id, type : type }),
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
});
request.success(function () {
target.closest('.notif-item').remove();
$scope.counter--;
});
request.error(function () {
// TODO
});
}
return friend;
})
This code has two methods: friend.delete() also friend.deleteAjax()
Calling functions from Factory:
.controller('FriendsController', ['$scope','$http', 'friendsFactory', function($scope, $http) {
$scope.deleteUser = function (idUser) {
friendsFactory.delete(idUser);
}
}])
I need decrement variable $scope.counter in friend.deleteAjax() ajax response, regardless controller from was called factory.
I can do duplicate in each controller:
$scope.counter = 10; and after call factory, but it is not good
Although the answer suggested by #JBNizet is absolutely correct but if you are bound to use the code in the way it is, then you can do two things. First is to simply pass the $scope from controller to service call (which is not a cleaner approach is not recommended):
$scope.deleteUser = function (idUser) {
friendsFactory.delete(idUser, $scope);
}
And you can use the scope inside the factory.
The second option to use current controller's scope to root scope and then use this in the factory.
In your controller
$scope.deleteUser = function (idUser) {
$rootScope.callingControllerScope = $scope;
friendsFactory.delete(idUser);
}
In your factory
friend.deleteAjax = function (event, id, type){
console.log($rootScope.callingControllerScope.counter);
// your code
}
And you also need to fix your dependency injection:
.controller('FriendsController', ['$scope','$http', 'FriendsFactory', function($scope, $http, friendsFactory) {
$scope.deleteUser = function (idUser) {
friendsFactory.delete(idUser, $scope);
}
}]);
You're doing many, many things wrong:
Using friendsFactoryinstead of FriendsFactory:
.controller('FriendsController', ['$scope','$http', 'friendsFactory'
here --------^
Forgetting to declare friendsFactory as an argument of the controller function:
.controller('FriendsController', ['$scope','$http', 'friendsFactory', function($scope, $http) {
here ----^
Accessing an undefined $scope variable in the service:
$scope.counter--;
^--- here
Doing DOM manipulation in a service...
The service responsibility is not to manipulate the DOM and the controller scope.
The DOM should be modified using directives in the html template.
The controller scope should be managed by the controller, not by the service. Return the promise request from the deleteAjax() function, and let the controller register a success callback, rather than doing it in the service. This callback will then be able to access the controller scope.
Note that most errors are basic JavaScript error that should be signalled by a good JavaScript editor, or at least by looking at errors in the console of your browser.

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);
});
});

AngularJS factory not working

I have abstracted my working code from a controller into a factory, but it doesn't seem to be working and I can't find what's wrong. I opted for a factory rather than a service because I wanted to execute some code that defined the variable before returning that variable; I want to get result.station (a part of the data returned by the API), not the full result.
This is my code:
var app = angular.module("myApp", []);
app.factory('api', ['$http',
function($http) {
var station_list = [];
$http({
method: 'GET',
url: 'http://api.irail.be/stations/?format=json&lang=nl'
})
.success(function(result) {
station_list = result.station;
});
return {
Stations: function() {
return station_list;
}
};
}
]);
app.controller("myController", ['api', '$scope',
function(api, $scope) {
$scope.station_list = api.Stations();
$scope.title = "Stations";
}
]);
and a working example.
Try this:
.success(function(result) {
angular.copy(result.station, station_list);
});
You had a small error, you were replacing the array instead of populating it. I used angular.copy instead of the assignment in your factory and it works
http://plnkr.co/edit/sqgKcFZAcClmkfdXHhrz
The problem is that you are dealing with asynchronous nature of AJAX.
I would suggest to have a delegate method in controller, which will be called when the service call is complete.
Something like the following:
app.controller("myController", ['api', '$scope',
function(api, $scope) {
api.Stations( function(station_list) {
$scope.station_list = station_list;
});
$scope.title = "Stations";
}
]);
The following is a service method excerpt:
return {
Stations: function(delegate) {
if (delegate)
delegate(station_list);
return station_list;
}
};

Resources