AngularJS: how to execute a method in another controller? - javascript

I've searched on Google but can't find information on how to do this properly. Seems like all the answers on Google are now outdated (using older versions of AngularJS).
I'm trying to setup two controllers on my AngularJS module. For example, the first controller is handling $http GET requests. And the second controller is displaying either a 'success' or 'error' message. I want to be able to call a method from the second controller with the success/error message that is to be displayed.
Or am I supposed to use a service/factory for this? I've read about services but can't figure out how to make something like this work.
var module = angular.module('app', []);
module.controller('ApiController', ['$scope', '$http', function ($scope, $http) {
$http.get('/api').
success(function(data){
// call AlertController('success')
}).
error(function(data){
// call AlertController('failed')
});
}]);
module.controller('AlertController', ['$scope', function ($scope) {
$scope.message = {
show_message: true,
type: 'info',
message: "Display message!"
};
}]);
Either doing it that way, or perhaps I would like to push the incoming alert onto a global object variable, and then remove it after it has been displayed.
Anyone know the proper way to set this up?

Ok let's try this - you should also check out Injecting $scope into an angular service function()
The Message service:
module.service('MessageService', function ($timeout) {
var messageQueue = [];
var DISPLAY_TIME = 5000; // each message will be displayed for 5 seconds
function startTimer() {
$timeout(function() {
// Remove the first message in the queue
messageQueue.shift();
// Start timer for next message (if there is one)
if (messageQueue.length > 0) startTimer();
}, DISPLAY_TIME);
}
function add(message) {
messageQueue.push(message);
// If this is the only message in the queue you need to start the timer
if (messageQueue.length==0) startTimer();
}
function get() {
if (messageQueue.length==0) return "";
else return messageQueue[0];
}
return { add: add, get: get };
});
You can still use this ApiService as well:
module.service('ApiService', ['$http', function ($http) {
return {
get: function(url) {
return $http.get(url);
}
};
}]);
Your Search controller:
module.controller('SearchController', ['$scope', 'ApiService', 'MessageService', function ($scope, api, messages) {
api.get('/yelp').
success(function(data){
messages.add('success');
}).
error(function(data){
messages.add('failed');
});
}]);
Your Alert controller:
module.controller('AlertController', ['$scope', 'MessageService', function ($scope, messages) {
$scope.getMessage = function() { messages.get(); }
}]);
So in your html you can have:
<div ng-controller="AlertController">
<div>{{ getMessage() }}</div>
</div>

here is how you make factory
module.factory('appService', ['$window', '$http', '$q', function(win, $http, $q) {
return{
backendcall: function(){
var deferred = $q.defer();
$http.get('/yelp').
success(function(data){
deferred.resolve(data);
}).
error(function(data){
deferred.resolve(status);
});
return deferred.promise;
}
}
}]);
and your controller will be like this
module.controller('AlertController', ['$scope', 'appService', function ($scope, appService) {
appService.backendcall().then(function(response){
$scope.message = {
show_message: true,
type: 'info',
message: "Display message!"
};
})
}]);

Related

Returning response from factory to controller in Angular

I have a factory that request user data via an api call:
angular.module('MyApp')
.factory('UserApi', function($auth,Account){
return {
getProfile: function()
{
Account.getProfile()
.then(function(response){
return response.data; ----> returning json data ok!!
});
}
}
});
But when i call the function in controller, it return me undefined
myApp.controller('AppCtrl', function($rootScope,$state,$window,$document,$scope,$filter,$resource,cfpLoadingBar,$translate,UserApi){
$scope.user = function(){
UserApi.getProfile().then(function(data){
$scope.currentUser = data;
})
}
console.log($scope.user()); ----> undefined
});
account factory:
angular.module('MyApp')
.factory('Account', function($http){
return {
getProfile: function(){
return $http.get('/api/me');
}
}
});
The error that log in console is TypeError: Cannot read property 'then' of undefined
EDIT
The only available solution is to set the response.data to $rootScope.user in which the data will be available across the controllers.
angular.module('MyApp')
.factory('UserApi', function($auth,Account,$rootScope){
return {
getProfile: function()
{
Account.getProfile()
.then(function(response){
$rootScope.user = response.data; ----> returning json data ok!!
});
return $rootScope.user;
}
}
});
First of all getProfile method should return a promise (not undefined like it's doing in your code):
angular.module('MyApp')
.factory('UserApi', function($auth,Account){
return {
getProfile: function()
{
return Account.getProfile()
.then(function(response) {
return response.data;
});
}
}
});
then in controller you should use then callback:
myApp.controller('AppCtrl', function ($rootScope, $state, $window, $document, $scope, $filter, $resource, cfpLoadingBar, $translate, UserApi) {
$scope.user = function () {
UserApi.getProfile().then(function (data) {
$scope.currentUser = data;
console.log($scope.currentUser);
})
};
});
Also make sure you understand the difference between synchronous and asynchronous code, and why console.log($scope.user()) makes no sense in this case: response if not yet available when you try to log it. Instead you provide a callback to be called when data has come.
You are trying to return the data after the request is completed successfully. But, since this is an ajax call we don't know when it will be completed (Basically, runs on a different thread.). There are two ways you can resolve this.
1 - Just return the call like so.
angular.module('MyApp')
.factory('UserApi', function($auth,Account){
return {
getProfile: function(){
return Account.getProfile(); // return call and resolve in controller.
}
}
});
2 - You can use promise ($q)
angular.module('MyApp')
.factory('UserApi', function($auth,Account, $q){
return {
getProfile: function(){
var deferred = $q.defer();
Account.getProfile()
.success(function(data){
deferred.resolve(data);
});
return deferred.promise; // just return the promise
}
}
});
and in your controller just have the following.
myApp.controller('AppCtrl', function($rootScope,$state,$window,$document,$scope,$filter,$resource,cfpLoadingBar,$translate,UserApi){
$scope.user = function(){
UserApi.getProfile().then(function(data){
$scope.currentUser = data;
console.log($scope.currentUser);
});
}
});
EDITED:
You get undefined. Because:
there isn't return in $scope.user
your console.log($scope.user($scope.user()) works only initial time.
there is time delay for getting data from UserApi.getProfile()
Also, your codes have some mistakes:
I can suggest that:
Don't use your console.log($scope.user()) initial time.
Or, You should get all data initial time when factory created. Then, you use UserApi.data in your controller.(But, there is time delay. You may get success data, if request return response before from loading of your controller).
.
angular.module('MyApp')
.factory('UserApi', function ($auth, Account) {
var data;
Account.getProfile().then(function (response) {
data = response.data;
});
return {
data: data
}
});
myApp.controller('AppCtrl', function ($rootScope, $state, $window, $document, $scope, $filter, $resource, cfpLoadingBar, $translate, UserApi) {
console.log(UserApi.data);
});

myfunction() function call from one controller to another in angularjs

i have used Angularjs and i wanna call getcustomer function from one controller to another controller i have so many doing gooogling but i don't have an idea that how to call that
i have write below code which i used
var app = angular.module('Napp', []);
app.controller('GetAlphabetical', function ($scope, $http) {
function getCutomers() {
$scope.loading = true;
$http.get('#Url.Content("~/Home/GetPesrons")').then(function (response) {
//var _data = angular.fromJson(response);
$scope.loading = false;
$scope.Customer = response.data; // please check the request response if list id in data object
}, function (error) {
throw error;
})
}
});
and second controller :
app.controller('MainCtrl', function ($scope, $http) {
getCutomers()
});
Mate, you will have to follow the following steps to resolve your problem. Firstly you have you create a factory
angular
.module('Napp')
.factory('CustomerFactory', ['$http', function ($http) {
var _factory = {};
_factory.getCustomers = function () {
return $http.get('#Url.Content("~/Home/GetPesrons")');
};
return _factory;
}]);
Then you can share data and functions between multiple controllers or services
GetAlphabetical Controller :
angular
.module('Napp')
.controller('GetAlphabetical', ['$scope', 'CustomerFactory', function ($scope, CustomerFactory) {
loadCustomers();
function loadCustomers() {
CustomerFactory.getCustomers().then(function (successResponse) {
$scope.Customer = successResponse.data; // please check the request response if list id in data object
}, function (errorResponse) {
throw error;
})
}
}]);
MainCtrl Controller :
angular
.module('Napp')
.controller('MainCtrl', ['$scope', 'CustomerFactory', function ($scope, CustomerFactory) {
loadCustomers();
function loadCustomers() {
CustomerFactory.getCustomers().then(function (successResponse) {
$scope.Customer = successResponse.data; // please check the request response if list id in data object
}, function (errorResponse) {
throw error;
})
}
}]);
This can be easily done by defining it as a service and injecting it as a dependency.
var app = angular.module('myApp', []);
myApp.service('helloWorldFromService', function() {
this.sayHello = function() {
return "Hello, World!"
};
});
app.controller('MainCtrl', function ($scope, $http, helloWorldFromService) {
app.controller('GetAlphabetical', function ($scope, $http, helloWorldFromService) {
Angular Service
What you want to do is to somehow communicate between two controllers. This can be easily be achieved using $broadcast & $on.
Incase there is a parent child relation between your controllers, use the following.
function firstCtrl($scope){
$scope.$broadcast('someEvent', [1,2,3]);
}
function secondCtrl($scope){
$scope.$on('someEvent', function(event, mass) {console.log(mass)});
}
If there is no parent child relationship between your controller, then inject $rootScope and broadcast using that.
related question - https://stackoverflow.com/a/14502755/1182982

Calling a Service function from a Controller in AngularJS

Controller Code
'use strict';
angular.module('MyApp').controller('ArticleContribEmailController', [
'$scope', 'ArticleAppState', 'fbsUserDataService', 'contribEmailService',
function ($scope, ArticleAppState, fbsUserDataService, contribEmailService ) {
this.userChanged = function () {
if (fbsUserDataService.initialized && fbsUserDataService.user && ArticleAppState.page_data) {
// user has authenticated.
contribEmailService.initForm();
}
};
// watch for when user data is available, run userChanged.
$scope.$watch(function() { return fbsUserDataService.user; }, this.userChanged);
$scope.$watch(function() { return fbsUserDataService.initialized; }, this.userChanged);
}
]);
Service Code
'use strict';
angular.module('forbesArticleApp').service('contribEmailService', [
'$injector', '$route', 'ArticleAppState', 'fbsUserFormFactory', 'fbsUserDataService',
function initForm ($injector, $route, ArticleAppState, fbsUserFormFactory, fbsUserDataService) {
console.log("Hello world!");
}
]);
I only want to fire the contribEmailService.initForm() function from the call in my controller, but it is firing as soon as the page loads.
How do I set when the service function initForm() is called?
Here is the corrected service code:
'use strict';
angular.module('forbesArticleApp').service('contribEmailService', [
'$injector', '$route', 'ArticleAppState', 'fbsUserFormFactory', 'fbsUserDataService',
function($injector, $route, ArticleAppState, fbsUserFormFactory, fbsUserDataService) {
return {
initForm: function() {
console.log("Hello world!");
}
};
]);
The service function is a factory that will in turn return the actual service. So it will run the first time it is requested as a dependency. The way you had it written, in fact, contribEmailService would have been undefined within your function, because your factory didn't actually return anything.
Hope this helps!
controller:-
blogcontroller is controller name
app.controller('blogController', function($scope, $compile, $http, blogAuth, AppInfo, $location,$element){
$scope.blog_abuse = function(blog_id)
{
blogAuth.BlogAbuse(blog_id).then(function(response)
{
$scope.DetailblogList.is_abused = response.records.is_abused;
},function(error){
});
}
});
service:-
app.factory('AppInfo', function(){
return {
serviceURL:site_url
};
});
app.service('blogAuth', function($http, $rootScope, $q, AppInfo){
this.BlogAbuse = function(blog_id){
var deferred = $q.defer();
var pageObj ={"blog_id":blog_id};
$http.post(AppInfo.serviceURL+'blog/blog_abuse',pageObj).success(function(data){
deferred.resolve(data);
}).error(function(msg, code) {
console.log('error', code, msg );
});
return deferred.promise;
}
});

AngularJS $scope.foo is set with service, but later on in the same controller undefined

I have a service which calls API and gets json response. I inject this service into my controller and try to set $scope.tank variable with this received data. When I try to use this variable later on (in the same controller!) it is undefined. But the funny thing is that data is displayed in the front-end.
I've looked all over stackoverflow and I can not figure this out. I have created a plunker example - http://plnkr.co/edit/DkFNE8E9897dSF19eaU9?p=preview
My service:
appServices.service('TankService', function($q, $http) {
var data, deferred = $q.defer();
return {
init: function(id) {
var defer = $q.defer();
$http.get(options.api.base_url, { cache: 'true'})
.success(function(response) {
data = response;
deferred.resolve(data);
});
},
// return promise
getData: function() {
return deferred.promise;
}
};
});
I call my data in controller like this:
appControllers.controller('TankViewCtrl', ['$rootScope', '$scope', '$q', '$routeParams', '$location', '$sce', '$route', 'TankService',
function TankViewCtrl($rootScope, $scope, $q, $routeParams, $location, $sce, $route, TankService) {
var id = $routeParams.tank_id;
$scope.id = id;
$scope.tank = [];
// call our data
TankService.init(id);
TankService.getData().then(function(data){
$scope.tank = data;
});
// why is this undefined?
console.log($scope.tank);
}
]);
Thank in advance for your help!
HTTP calls are asynchronous requests.
You're asking your controller to display the result of the request without making sure you had an answer beforehand. That's why you get undefined.
Use :
TankService.getData().then(function(data){
$scope.tank = data;
console.log($scope.tank);
});

Best practice to set up a service or factory for $http contacting to REST API in AngularJS

I've created $http and REST API interface in AnguarJS service as a function that gets injected into different controllers like this:
// Global service to share between states
.service("appSharedService", ['$http', function($http) {
// Method: Returns list of all cities.
this.restCitiesGet = function() {
return $http.get('http://example/nkhorasaniec7/api/v0/city');
};
// Method:
this.citiesGet = function() {
this.restCitiesGet().success(function (data) {
console.log(data);
return data;
})
};
}])
console.log(data); returns the right json output when I call citiesGet() .
// Main controller that prints list of cities.
.controller('CityList', ['$scope', function($scope, appSharedService) {
$scope.cities = appSharedService.citiesGet();
console.log($scope.cities);
}]);
This is my controller injecting my service. console.log($scope.cities); here returns undefined.
$scope.cities value doesn't get changed after route calls this controller.
Is there something wrong with my setup?
Something interesting is that after I change route and come back to this controller again, this time $scope.cities have my REST data and everything's fine.
I think there's something wrong with timing or asynchronous functionality problem here that I'm not aware of.
EDIT:
I could have had $http in my controller and this works all well:
.controller('CityList', ['$scope', '$http', function($scope, $http, appSharedService) {
$http.get('http://localhost/nkhorasaniec7/api/v0/city').success(function (data) {
$scope.cities = data;
});
}]);
But I want to implement helper functions for this.
I would say that the common approach would be to return the promise directly to the controller, much like you have mentioned above by directly using the http request.
// Global service to share between states
.service("appSharedService", ['$http', function($http) {
// Method: Returning the promise
this.citiesGet = function() {
return $http.get('http://example/nkhorasaniec7/api/v0/city');
};
}])
Controller:
.controller('CityList', ['$scope', '$http', function($scope, $http, appSharedService) {
appSharedService.citiesGet().success(function (data) {
$scope.cities = data;
});
}]);
I think you are right about the timing issue. From what I understand, you are getting a promise, that at the moment you do console.log($scope.cities) is not yet resolved.
If you use $scope.cities inside your page, you should see the results as soon as they are loaded. Another option would be to use the promise then function if you really want to log.
$scope.cities = appSharedService.citiesGet().then(function(data) {
console.log(data);
return data;
};
Answering my own question:
I'm trying to make this happen in my a controller defined in my view using ng-controller, not a controller linked to a router (otherwise you could use resolve property like this Delaying AngularJS route change until model loaded to prevent flicker).
And I want to use REST using $http as a factory/service helper function for a cleaner code.
// Global service to share between states
.service("appSharedService", ['$http', '$q', function($http, $q) {
this.citiesGet = function() {
var deferred = $q.defer();
$http({method: 'GET', url: 'http://localhost/nkhorasaniec7/api/v0/city'}).success(function(data) {
deferred.resolve(data);
}).error(function(data, status) {
deferred.reject(data);
});
return deferred.promise;
};
}])
I used angular $q promise here.
// Our main controller that prints list of cities.
.controller('CityList', ['$scope', 'appSharedService', function($scope, appSharedService) {
var promise = appSharedService.citiesGet();
promise.then(
function(data){$scope.cities = data;}
,function(reason){alert('Failed: ' + reason);}
);
}])
And used then function to use that promise.
And now it always updates $scope.cities in any situation that template loads (not just in ng-view)
You can use $q service
.service("appSharedService", ['$http', '$q', function($http, $q) {
// Method: Returns list of all cities.
this.restCitiesGet = function() {
var deffered = $q.defer();
$http.get('http://example/nkhorasaniec7/api/v0/city').then(
//success
function(response){
deffered.resolve(response.data);},
//error
deffered.reject();
);
return deffered
};
and after that you can use promise in you controller
.controller('CityList', ['$scope', function($scope, appSharedService) {
$scope.cities = []
appSharedService.citiesGet().then(
//success
function(result){
angular.copy(result, $scope.cities)
console.log($scope.cities);
},
//error
function(){
console.log("load error");
});
}]);

Categories