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.
Related
I have my notification listener in the run function. When a notification is received I need to update a object present in $scope with a parameter present in notification object.
angular.module('app', ['ionic', 'chatsCtrl'])
.run(function($state, $ionicPlatform) {
window.FirebasePlugin.onNotificationOpen(function(notification) {
// Need to append this notification.parameter to a scope variable present in a controller
}
}
.controller('chatsCtrl', function($scope) {
// $scope.chats
});
How can I go about doing this? I don't want to use $rootScope object as $scope.chat object will get very heavy.
Thanks
you can't call scope variables/functions inside run block. since you don't want to use rootscope my suggestion is to create a service and assign values to a particular method in that service from the run block. Then get that value from the controller using the same service.
angular.module('app', ['ionic', 'chatsCtrl'])
.run(function($state, $ionicPlatform) {
window.FirebasePlugin.onNotificationOpen(function(notification) {
sampleService.setData(notification)
}
}
.controller('chatsCtrl', function($scope,sampleService) {
$scope.chats = sampleService.getData()
});
.factory('sampleService', function() {
var data;
return {
getData : function(){ return data},
setData: function(param){ data = param},
}
});
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!
I am facing following problem:
In my AngularJS application, I have service, which includes data and a function, which refreshes them
angular.module('testService', ['ui.router'])
.factory('testService', function($http) {
var service = {};
var _baseUrl = 'http://127.0.0.1:8000/api/v1/test/';
service.orders = {created: 0, approved: 0};
/*
* get number of unprocessed orders
*/
service.updateNOrders = function(){
var tableName = 'orders?stats=true';
$http({
method: 'GET',
url: _baseUrl + tableName,
}).success(function(data){
service.orders = data;
console.log(data);
return;
}).error(function(err){
alert(JSON.stringify(err));
return;
})
}
});
I can inject this service to i.e. directive and call the function updateNOrders to update the data from the directive.
What I want, though, is for service to call this function every n seconds.
The service is shared in several directives and instead of every directive, taking care of updating the data, I would like the service to do it itself.
I have tried comething like:
angular.module('testService', ['ui.router'])
.factory('testService', function($http, $q, $rootScope, $interval) {
$interval(console.log('test'),1000);
/*
rest of the code
*/
});
but that does not work.
So - Is it possible to call the function updateNOrders inside testService every minute or so?
Creating service with side effect is the bad idea. Better off create service with method which sets your interval with callback. Then you can inject your service in run callback (run calls callback only once):
angular.module('testService', ['ui.router'])
.factory('testService', ['$interval', function($interval) {
var service = {};
service.doPeriodicAjaxRequest = doPeriodicAjaxRequest;
function doPeriodicAjaxRequest() {
$interval(yourCode, ...);
}
return service;
}]);
Then:
angular.module('', [])
.run(['testService', function (testService) {
testService.doPeriodicAjaxRequest();
}]);
Why dont you call the service function from controller in certain interval of time.
$interval(testService.functionName,1000);
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);
});
});
I'm all new to AngularJS and need some help, I have a "AppCtrl" and from there I have a HTTP webservice call - and need the webservice call response accessible in my other controllers.
angular.module('starter.controllers', [])
.controller('AppCtrl', function($scope, $http) {
$scope.webservice_url = "http://webserviceurl.com/";
$http.get($scope.webservice_url+"?action=get_settings").success(function(data, status, headers, config) {
$scope.stations = data.stations;
});
})
This works FINE - and i can access the $scope.stations in my templates - BUT now i want to access the $scope.stations in my "PlaylistCtrl" controller, but this is undefined :(
.controller('PlaylistCtrl', function($scope, $stateParams) {
console.log($scope.stations); // is undefined :(
})
How can I make sure the http call is "done" (success) before the "PlaylistCtrl" is loaded ...
you should turn the http into service/factory if possible
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope, dataService) {
dataService.then(function (data) {
$scope.data = data
})
});
app.controller('SecondCtrl', function($scope, dataService) {
dataService.then(function (data) {
$scope.secData = data
})
});
app.service('dataService', function ($http, $q){
var defferer = $q.defer()
$http.jsonp('http://ip.jsontest.com/?callback=JSON_CALLBACK').success(function (data){
defferer.resolve(data)
})
return defferer.promise
})
http://plnkr.co/edit/8k97DngZ8KoFOBPFJG82?p=preview working example
$scope.stations ist not undefined in PlayListCtrl because the HTTP call has not finished, but because PlayListCtrl has a different $scope than AppCtrl.
You should put the webservice call into a service and inject that service into all controllers that require it.
In Angular, you don't wait for data before rendering. You let it render, even if the array is empty initially, and then once the data returns, you render again. Angular does this to maintain a high level of responsiveness. It is by design, and not something you should try to change.
All you need to do to fix your undefined variable is initialize the stations scope variable in your controller. Although it gets overwritten when the data returns from your service, it doesn't matter because angular will watch for changes to the scope variable by reference and update all views when it does.
angular.module('starter.controllers', [])
.controller('AppCtrl', function($scope, $http) {
$scope.webservice_url = "http://webserviceurl.com/";
$scope.stations = [];
$http.get($scope.webservice_url+"?action=get_settings").success(function(data, status, headers, config) {
$scope.stations = data.stations;
});
})
In your inner controller, if the data hasn't returned yet, $scope.stations will be an empty array:
.controller('PlaylistCtrl', function($scope, $stateParams) {
console.log($scope.stations); // is []
$scope.$watch('stations', function(newVal) {
alert('data returned!! updating views!');
});
})
Once the data returns, the array reference on the scope is overwritten, any $watch handlers are called to update the view.
// Make a remote request.
$http.get('some wonderful URL for a service').success(function (results) {
superImportantInfo = results;
semaphore = true;
});
while (!semaphore) {
// We're just waiting.
}
This is how you can let your controller to wait till it finishes execution of controller 1 and before moving to the next controller.
Hope this help!