AngularJS call common controller function from outside controller - javascript

My basic premise is I want to call back to the server to get the logged in user in case someone comes to the site and is still logged in. On the page I want to call this method. Since I am passing the user service to all my controllers I don't know which controller will be in use since I won't know what page they're landing on.
I have the following User Service
app.factory('userService', function ($window) {
var root = {};
root.get_current_user = function(http){
var config = {
params: {}
};
http.post("/api/user/show", null, config)
.success(function(data, status, headers, config) {
if(data.success == true) {
user = data.user;
show_authenticated();
}
});
};
return root;
});
Here is an empty controller I'm trying to inject the service into
app.controller('myResourcesController', function($scope, $http, userService) {
});
So on the top of my index file I want to have something along the lines of
controller.get_current_user();
This will be called from all the pages though so I'm not sure the syntax here. All examples I found related to calling a specific controller, and usually from within another controller. Perhaps this needs to go into my angularjs somewhere and not simply within a script tag on my index page.

You could run factory initialization in run method of your angular application.
https://docs.angularjs.org/guide/module#module-loading-dependencies
E.g.
app.run(['userService', function(userService) {
userService.get_current_user();
}]);
And userService factory should store authenticated user object internaly.
...
if (data.success == true) {
root.user = data.user;
}
...
Then you will be able to use your factory in any controller
app.controller('myController', ['userService', function(userService) {
//alert(userService.user);
}]);

You need to inject $http through the factory constructor function, for firsts
app.factory('userService', function ($window, $http) {
var root = {};
root.get_current_user = function(){
var config = {
params: {}
};
$http.post("/api/user/show", null, config)
.success(function(data, status, headers, config) {
if(data.success == true) {
user = data.user;
show_authenticated();
}
});
};
return root;
});
in your controller you can say
$scope.get_current_user = UserService.get_current_user();
ng attributes in your html if needed. besides this, i am not sure what you need.

Related

AngularJS - How to cache service`s ajax result to reuse in controller

I was recomended to use Angular services in order to centralize many repetative functions that were store in my controller, so I am rewriting my code using services now.
It seemed simple at first but cant seem to find a good structure to fetch my ajax data (only once), then store it in my service for my controller to reuse the cached data when ever it needs it. At the moment I keep getting errors saying: TypeError: Cannot read property 'sayHello' of undefined.
I believe this is because theres is a delay to fetch my ajax data via my service before the controller loads. Im not quite certain how I can optimize this. Would anyone have a better stucture to this?
Service:
app.service('MyService', function ($http) {
this.sayHello = function () {
var deferred = $q.defer();
$http({
method: 'GET',
url: 'AJAX PATH',
headers: { "Accept": "application/json;odata=verbose;charset=utf-8"}
}).then(function(data){
var configurations = data;
var configurations.data_result_1 = configurations.data_result_1.split("\r\n");
var configurations.data_result_2 = configurations.data_result_2.split("\r\n");
deferred.resolve(configurations);
}
return deferred.promise;
};
this.sayHello(); //Run the function upon page laod.
});
Controller:
app.controller('AppController', function (MyService, $scope) {
$scope.configurations = null;
$scope.configurations = function() { MyService.sayHello() };
});
I recommend you to use another way to declare the service:
app.factory("MyService", function($http){
var configurations = {};
$http({
method: 'GET',
url: 'AJAX PATH',
headers: { "Accept": "application/json;odata=verbose;charset=utf-8"}
}).then(function(data){
configurations = data;
configurations.data_result_1 = configurations.data_result_1.split("\r\n");
configurations.data_result_2 = configurations.data_result_2.split("\r\n");
});
return {
getConfigurations: function(){
return configurations;
}
}
In your controller you can use a $watch, then when the configurations objects changes you take the information:
.controller("YourCtrl", function($scope,MyService){
var vm = this;
vm.configurations = {};
$scope.$watchCollection(function () { return MyService.getConfigurations()},function(newValue){
vm.configurations = newValue;
});
Totally agree with Bri4n about store configuration in the factory. Not agree about the controller because you said you don't want to watch, but only load data once.
But you $http already return a promise so as Brian said this is nice (just $q is useless here so you can delete it from injection). And I just wrapped http call in function, and the exposed function just check if configurations are already loaded. If yes, just return configurations else load it and then return it.
app.factory("MyService", function($http,$q){
var configurations = {};
function loadConfig(){
$http({
method: 'GET',
url: 'AJAX PATH',
headers: { "Accept": "application/json;odata=verbose;charset=utf-8"}
}).then(function(data){
configurations = data;
configurations.data_result_1 = configurations.data_result_1.split("\r\n");
configurations.data_result_2 = configurations.data_result_2.split("\r\n");
});
}
return {
getConfigurations: function(){
If( !!configurations ){
return configurations;
}
//Else loadConfig.then return configurations
}
}
In your controller you can just get config without need to know if it is already loaded.
.controller("YourCtrl", function(MyService){
var vm = this;
// If configurations already loaded return config, else load configurations and return configurations.
vm.configurations = MyService.getConfigurations();
I write on my phone so my code is not perfect I can't write properly.
OK, on second thought, it looks like you are not using the dependency array notation properly. Change your code to:
app.service('MyService', ['$http', function ($http) {
// do your stuff here
}]);
and for the controller:
app.controller('AppController', ['MyService', '$scope', function(MyService, $scope) {
// do your stuff here
}]);

Send POST request and get items in Angular

Im writing my first app with Angular and now faced up with the problem... I have address for POST request with authentication token. Something like:
http://example.com/orders?authentication_token=123456
So I need to make ng-submit or ng-click that send that request and get a bunch of items and show them on the page...
Also, I have a body for them:
{
"order": {
"seller_id":84,
"price":123,
"delivary_date":"12-12-2025",
}
}
So, what the best way to do that?
So you will have to make one angular service which would communicate with server and fetch the data and one angular controller which will interact with service to get the data and display over the UI.
Lets say service name is MyService:
app.service('MyService', function($http) {
var params = {}; // some parameters
this.getData = function(successCallback, failureCallback) {
$http.post("URL", params).then(function(data) {
successCallback(data);
}, function(data, status) {
failureCallback(data, status);
});
}
});
Controller name is MyCntrl:
app.controller('MyCntrl', function($scope, MyService) {
function successCallback(data) {
$scope.itemList = data;
}
function failureCallback(data, status) {
$scope.itemList = {};
}
$scope.handleClick = function() {
MyService.getData(successCallback, failureCallback);
}
});
I believe it would help you to resolve your requirement!!!
Assume you have a orderCtrl. ng-click or ng-submit is based on your app requirement. Call the function someFunction() that triggers $http post and you can handle the success and failure response.
app.controller('orderCtrl', function($scope, $http) {
$scope.someFunction = function(){
var data = {}; // prepare your data here.
$http({
method : "POST",
url : "specify your url here",
data : data
}).then(function mySucces(response) {
var response = response.data;
// handle your success here
}, function myError(response) {
// handle the failure here
});
});
});
Note :
If you are using a form and you want to trigger this function after user filling all the information, then use ng-submit. If it is independent then use ng-click.
I'm saying again, it's all depends on what you are doing.

angularjs / javascript how to update factory created singleton

I'm pretty new to angularjs and javascript so I'm hoping you can help me figure this out. I have a factory creating a service singleton and I want it to subscribe to some events and update itself when those occur.
However, I'm not sure how to get a reference to the object created by the factory in this context. See "My Problem" in a code comment.
I would also appreciate any and all feedback on the way I'm using angular/js and what I could be doing better.
(function () {
'use strict';
var coreMod = angular.module('CoreMod',['ng']);
coreMod.factory('accountService', accountService);
accountService.$inject=['$rootScope',
'$log',
'$http',
'$q',
'$localStorage',
'$sessionStorage',
'authService'];
function accountService($rootScope, $log, $http, $q, $localStorage, $sessionStorage, authService) {
var accountService = {
CurrentAccount: null,
logOut: logOut,
_logIn: userLoggedIn//anyway to hide this?
};
$rootScope.$on('userLoggedIn', accountService._logIn);
return accountService;
function userLoggedIn() {
$http({ method: 'get', url: msApiUrl + '/account/userinfo', timeout: 3000, warningAfter: 50 })//TODO: find a way to make these timinings default
.success(function (result) {
$log.info('User logs into api server successfully and gets response: ' + result);
handleLoginMessage(result);
}).error(function (result) {
$log.warn('Error logging into api server. Response: ' + result);
$rootScope.$broadcast('CriticalError', 'Error logging into api. Please clear your cache and try again. If this occurrs again please contact your system administrator. ');//TODO: configurable and localized message
});
};
function handleLoginMessage(message) {
var accountService = this; //my problem: this is undefined
accountService.CurrentAccount={};
accountService.CurrentAccount.emailHash = message.EmailHash;//TODO: are these case sensitive / can I control that
accountService.CurrentAccount.organizationId = message.OrganizationId;
accountService.CurrentAccount.username = message.Username;
$localStorage.userInfo = accountService;
};
function logOut() {
authService.logOut();
$sessionStorage.$reset();
$localStorage.userInfo = null;
};
}
}());
You don't need the code line at all. Just remove:
var accountService = this;
accountService is an object literal that you have created with var accountService = {...} and your function handleLoginMessage is in the same scope. So the accountService variable should be accessible with-in handleLoginMessage.
If you want to hide _logIn: userLoggedIn then remove it from accountService object but then it is not accessible from outside of your service. Everything that's inside of accountService will be exposed to other controllers, services or factories that are injecting your factory.

How to use a service with Http request in Angular JS

I'm using AngularJS to build my web application, I've been always using controllers to make HTTP request, which makes things easier and clear for me.
But for a better code structure, and better execution for my application, I wanted to use services instead of controllers to use the web service.
I tried to make :
var app = angular.module('ofcservices', []);
app.factory('news', ['$http', function ($http) {
var news={};
news.getnews= function () {
return $http.get('http://int.footballclub.orange.com/ofc/news?offset=0&limit=5');
};
return news;
}]);
and the code of the controller :
.controller('news', function($scope, ofcservices) {
$scope.news = ofcservices.getnews();
})
Everything seems to be right ?
ofcservices.getnews() is a promise You need manage with the function sucess and error
ofcservices.getnews().
success(function(data) {
$scope.news=data
}).
error(function(data, status, headers, config) {
//show a error
});
As weel change app.factory('news' to app.factory('newsFactory' and call it in controller('news', function($scope, newsFactory) {
You can get more data about promise in the angular documentation
The concept is more or less right, but you should use the callback functions to handle the $http response correctly.
But your controller and service have the same name news, which is BAD :-) and you need to inject the newsService and not the module name.
.controller('newsController', function($scope, newsService) {
newsService.getnews().then(
function(newsData) {
$scope.newsData = newsData
},
function optionalErrorhandler() {});
})
angular
.module('MyApp', [])
.controller('MyController', MyController)
.factory('MyService', MyService);
MyController.$inject = ['$scope','MyService'];
MyService.$inject = ['$http'];
function MyService($http){
var service = {
var myServiceFunction : function(){
$http({
// your http request on success return the data.
}).success(function(data)){
return data;
});
}
};
return service;
}
function MyController($scope, MyService){
MyService.myServiceFunction(); //Call service from the controller.
}

use angular factory to hold a value for rest of application to access to minimize server calls

I have the following factory:
angularModule
.factory('ArticleCategoryService', function ($http, $q) {
// Service logic
// ...
var categories = [];
var _getCategories = $http.get('/api/articles/category').success(function (_categories) {
categories = _categories;
});
// .error( function (data, status, headers, config) {
// });
// Public API here
return {
getCategories: function () {
var deferred = $q.defer();
deferred.resolve(_getCategories);
return deferred.promise;
}
};
});
and this is the section that calls this service in the controller:
// Calls the getCategories function from the ArticleCategory Service,
// Will return a promise
ArticleCategoryService.getCategories()
.then(function (categoriesResult) {
$scope.categories = categoriesResult.data;
}, function (err) {
console.log(err);
});
This works but there will be a GET call to the server every time user comes back to this view/state and the categories object that belongs to the factory is never used.
I'm trying to make it so that it will return the categories variable in the factory singleton, and have it initialize on site load (or from first GET call).
But if I just return categories when user calls getCategories, it will return nothing since we need time for the $http call.
Check if categories is defined, and resolve the promise with the variable rather than the GET request if it is:
return {
getCategories: function () {
var deferred = $q.defer();
if (categories.length > 0) {
deferred.resolve(categories);
} else {
deferred.resolve(_getCategories);
}
return deferred.promise;
}
};
I'm doing exactly same thing on my app. I have a main module and a main controller within it that wraps any other controllers, so its scope is persistent over views.
In this main controller you could assign the factory's getCategory() data to a scope variable and then you could use that in your entire app, because the scope will be inherited to child scopes.
angularMainModule
.factory('ArticleCategoryService', function ($http) {
var ArticleCategoryServiceMethods = {};
//fn: getCategories
ArticleCategoryServiceMethods.getCategories = function(fromWhere){
return $http.get(fromWhere)
.then(function(res){
return res.data;
}, function(err){
return err.status;
});
}
return ArticleCategoryServiceMethods;
}
angularMainModule
.controller('MAINCTRL', function($scope, ArticleCategoryService) {
//get all categories
$scope.categories = ArticleCategoryService.getCategories('/api/articles/category');
//... the rest of the main ctrl code ... //
}
... when you define the main module, make sure you inject the rest of your modules in it
var angularMainModule = angular.module('angularMainModule', [
'ngRoute',
'ngTouch',
'ngAnimate',
//< ng - etc >,
'Module1',
'Module2',
//< module - n >
]);
...and the markup (i'm bootstrapping my angular app manually, but you could add the ng-app="angularMainModule" attribute on the html tag if you're doing it that way):
<html ng-controller="MAINCTRL">
<!-- head data -->
<body>
<div id="page" ng-view></div>
If you want to make sure data is loaded before your app opens the main page, you could add that service call in the routeProvider block of your app (on the default route), so when the MAINCTRL will be loaded the data will be already there, ready to be assigned.
angularModule
.factory('ArticleCategoryService', function ($http) {
// Service logic
// ...
var categories = [];
$http.get('/api/articles/category').success(function (_categories) {
categories = _categories;
});
// Public API here
return {
categories: categories
};
});
angularModule
.controller('ControllerMain', function($scope, ArticleCategoryService) {
$scope.categories = ArticleCategoryService.categories;
});

Categories

Resources