I am setting a local storage value in a AngularJS Service and trying to get the value in a AngularJS controller. But In the controller, getting null value instead of the value I have set in the service.
Here is the service where I have set the local storage value:
app.factory('accountService', ['$http', '$q', 'serviceBasePath', 'userService', '$window', function ($http, $q, serviceBasePath, userService, $window) {
var fac = {};
fac.login = function (user) {
var obj = { 'username': user.username, 'password': user.password, 'grant_type': 'password' };
Object.toparams = function ObjectsToParams(obj) {
var p = [];
for (var key in obj) {
p.push(key + '=' + encodeURIComponent(obj[key]));
}
return p.join('&');
}
var defer = $q.defer();
$http({
method: 'post',
url: serviceBasePath + "/token",
data: Object.toparams(obj),
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}).then(function (response) {
userService.SetCurrentUser(response.data);
// The local storage value I have set
localStorage.setItem('IsAuthenticated', true);
localStorage.setItem('userName', response.username);
defer.resolve(response.data);
}, function (error) {
defer.reject(error.data);
})
return defer.promise;
}
fac.logout = function () {
userService.CurrentUser = null;
userService.SetCurrentUser(userService.CurrentUser);
}
return fac;
}])
Here is the controller where I am trying to get the previously set local storage value:
app.controller('indexController', ['$scope', 'accountService', '$location', '$window', function ($scope, accountService, $location, $window) {
$scope.message = localStorage.getItem("IsAuthenticated");
console.log($scope.message);
$scope.logout = function () {
accountService.logout();
$location.path('/login');
}
}])
Problem is I am getting null value instead of the value I have set in the service.
Any Help Please!
Best way to deal with browser storage using angular is:
1) Create a service that deals with localStorage, sessionStorage, cookie with generic methods that exposed through service.
2) This service will consumed by controller specific service, this service also handles keys that going to used to store in storage.
3) This service will expose more specific methods that consumed by controller.
eg:
UserController:
userService.setUserSession(session)
UserService:
var SESSION_KEY = 'userSession';
setUserSession() {
storageService.sessionStorageProvider.set(SESSION_KEY, session)
}
StorageService:
// here you need to create generic method using inheritance which will expose sessionStorage and loacalStorage and cookieStorage.
First try to get this in factory itself..after setting it...if you are able to get there then surely you will get in controller as well. Because local Storage nothing to relate with factory or controller.
Try like this , Use $window.
$window.localStorage.setItem('userName', response.username);
I believe you need to inject the dependency into your factory:
app.factory('accountService', ['$http', '$q', 'serviceBasePath', 'userService', '$window', '$localStorage', function ($http, $q, serviceBasePath, userService, $window, $localStorage) {
var fac = {};
fac.login = function (user) {
var obj = { 'username': user.username, 'password': user.password, 'grant_type': 'password' };
Object.toparams = function ObjectsToParams(obj) {
var p = [];
for (var key in obj) {
p.push(key + '=' + encodeURIComponent(obj[key]));
}
return p.join('&');
}
var defer = $q.defer();
$http({
method: 'post',
url: serviceBasePath + "/token",
data: Object.toparams(obj),
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}).then(function (response) {
userService.SetCurrentUser(response.data);
// The local storage value I have set
$localStorage.IsAuthenticated = true;
$localStorage.userName = response.username;
//localStorage.setItem('IsAuthenticated', true);
//localStorage.setItem('userName', response.username);
defer.resolve(response.data);
}, function (error) {
defer.reject(error.data);
})
return defer.promise;
}
fac.logout = function () {
userService.CurrentUser = null;
userService.SetCurrentUser(userService.CurrentUser);
}
return fac;
}])
Related
I currently have 2 javascript controllers: selectAll and listAllDomains.
I'm trying to call the method getBeanName (defined in listAllDomains) in the controller selectAll under:
response = $http.post('/invoke/selectAll/', INSERT_CALL_HERE);
As a note, the object returned by the method getBeanName will be passed as an argument to the $http.post() method and handled by a Java controller.
app.controller('listAllDomains', ['$http', '$scope', '$rootScope', function ($http, $scope, $rootScope) {
$scope.showSpinner = true;
$scope.showBtn = false;
let dataObj;
$http.get('domains/').then(function (response) {
$scope.showSpinner = false;
$scope.domains = response.data;
});
$scope.showButton = function(eleStatus) {
let eleSize = Object.keys(eleStatus).length;
return !eleSize;
};
$scope.getBeanName = function (objectType, objectName) {
dataObj = {
type : objectType,
name : objectName,
methodName : "select",
methodParameters : ["true"]
};
localStorage.setItem("dataObj", dataObj);
console.log(dataObj);
$rootScope.$emit("invokeSelectAll", dataObj);
return dataObj;
}
}]);
app.controller('selectAll', ['$http', '$scope' , '$rootScope',
function ($http, $scope, $rootScope) {
var response;
$rootScope.$on("invokeSelectAll", function(){
$scope.invokeSelectAll();
});
$scope.invokeSelectAll = function(){
console.log(localStorage.getItem("dataObj"));
response = $http.post('/invoke/selectAll/', INSERT_CALL_HERE);
response.success(function(data, status, headers, config) {
$scope.responses = data ? data : "Select Operation not supported on this bean";
});
}
}]);
Any help would be much appreciated! Thank you!
You can either create a service and inject it in both controllers or just define your function in $rootScope and then use it in any controller.
Check this issue for reference: How to use $rootScope in AngularJS
first create a service/factory with required function. And inject into the controller.
I have a function that is triggered when my page is loaded and i get the data
app.run
(function ($rootScope, AUTH_EVENTS, PAGES_PERMISSION, AuthService) {
$rootScope.$on('$routeChangeStart', function (event, next) {
if(!AuthService.isAuthenticated()){
var userStorage = localStorage.getItem("user_id");
if(userStorage != null){
// I want to store userData on my $scope as currentUser
var usedData = AuthService.isLogged(userStorage);
}
app.factory('AuthService', function ($http, $rootScope,Session, AUTH_EVENTS) {
var authService = {};
authService.isLogged = function (userId) {
return $http({
method: 'POST',
url: API_ROOT_SERVER_ADDRESS + "/isLogged",
headers : {'Content-Type': 'application/x-www-form-urlencoded'},
transformRequest: function(obj) {
var str = [];
for(var p in obj)
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
return str.join("&");
},
data : {userId : userId}
}).then(function successCallback(res) {
Session.create(res.data.student_id, r es.data.user_name,res.data.profile);
return res.data;
}, function errorCallback(response) {
console.log("errorCallback in response");
});
};
return authService;
})
app.controller('LoginController', function($scope, $rootScope,$routeParams,
LoginService, $location, $window, $http, AUTH_EVENTS, AuthService) {
$scope.user = {
username: "",
password : ""
};
$scope.login = function (user) {
AuthService.login(user).then(function (user) {
$rootScope.$broadcast(AUTH_EVENTS.loginSuccess);
$scope.setCurrentUser(user);
}, function () {
$rootScope.$broadcast(AUTH_EVENTS.loginFailed);
});
};
});
now i want to store userData (or res.data in AuthService) in my $scope, but the only place i can manipulate $scope is on my controllers according to my research. I tried to inject $scope and LoginContorller to my factory and app.run and got there errors:
LoginControllerProvider <- LoginController <- AuthService
Unknown provider: $scopeProvider <- $scope
How can i store the value that came from my request in my $scope since my call is triggered from app.run and not from any controller as usual?
I followed the comments from #k102 and managed to solve my problem adding the fragments of code bellow:
1- Created getters and setters in my AuthService
2- Set the data after my API request
3- Applied the value on my scope from controller
//AuthService setters
authService.setData = function(data){
this.authData = data;
console.log(this.authData);
}
authService.getData = function(){
console.log(this.authData);
return this.authData;
}
//AuthService request
then(function successCallback(res) {
authService.setData(res.data);
//LoginController
$scope.setCurrentUser(AuthService.getData());
I am new to Angularjs and studied a lot. But I stuck at a point. Google doesn't help me. I have a controller and I have data in $scope.results
app.controller('manage_categories', function($scope, $http, $filter, $window) {
$scope.results = [];
$http({
url: base_url + 'employee/fetchData?table=results',
method: "POST",
}).success(function(data) {
$scope.results = data;
});
})
now i want to access the same in other without any other $http call. I have done with another call but i don't want this . because i need this in many other controllers.something like this
app.controller('manage_users', function($scope, $http, $filter, $window,results) {
$scope.results = results;
//~ $http({
//~ url: base_url + 'employee/fetchData?table=results',
//~ method: "POST",
//~ }).success(function(data) {
//~ $scope.results = data;
//~ });
})
or any other method. Thanks.
update
I tried this
var myApp = angular.module('myApp',[]);
myApp.factory('results', function() {
return {
name : [{id:21,name:'this is test'}]
};
});
app.controller('manage_users', function($scope, $http, $filter, $window,results) {
$scope.results = results;
})
This is working fine . But not working with $http call .
var myApp = angular.module('myApp',[]);
myApp.factory('results', function($scope,$http) {
$scope.results=[];
$http({
url: base_url + 'employee/fetchData?table=results',
method: "POST",
}).success(function(data) {
$scope.results = data;
});
return {
name : results
};
});
update 2
after answers i write it like
var canapp = angular.module('canApp', ["ngRoute", "angularFileUpload"]);
canapp.service('ResultsFactory', ['$http', function($http) {
// http call here
var url=base_url + 'employee/fetchData?table=results';
$http.post(url,data).success(function(data){
this.results = data;
});
}])
call like this
canapp.controller('get_candidates', function($scope, $http, $filter, $timeout, $window, ResultsFactory) {
$scope.check=ResultsFactory.results;
});
but it is not setting the value in template
Use $broadcast to share the data between controllers. Your code will look like this
app.controller('manage_categories', function($scope, $http, $filter, $window, $rootScope) {
$scope.results = [];
$http({
url: base_url + 'employee/fetchData?table=results',
method: "POST",
}).success(function(data) {
$scope.results = data;
$rootScope.$broadcast("results",data);
});
});
app.controller('otherCtrlr', function($scope, $rootScope) {
$rootScope.$on("results", function(event, data){
$scope.results = data;
});
});
But using a service call in the controller is not a best approach. Create a factory and create a method to call your service.
From controller you need to call this method. But to avoid two service calls, you definitely need to use broadcast/emit(depending on data transfer is from parent or child)
There are various possible way of communicating between two controllers. If you just Google share data between controllers angularjs, you may found various links:
Using Services to Share Data Between Controllers
Sharing Data Between Controllers
Share data between AngularJS controllers
Passing data between controllers in Angular JS?
So, in short, possible ways are:
Using Angular Factories (recommended)
Using $rootScope (not recommended)
Using top most controller's scope as root scope
You can do this:
app.factory('ResultsFactory', resultsFactory);
resultsFactory.$inject = ['$http'];
function resultsFactory = function(){
var self = {};
var results = null;
self.getResults = function(){
if(!results){
$http.post(url,data).success(function(data){
results = data;
});
}else{
return results;
}
}
return self;
}
Only the first time that you call to ResultsFactory.getResults() this executes the $http call.
Here's a small fiddle explaining how to share data between controllers.
https://jsfiddle.net/frishi/zxnLwz6d/10/
(Check the browser console to see that both controllers can access data via the service.)
Basically the premise of a service is that it is a singleton that can be used by all the controllers registered on your module.
You want to make that $http call in a service:
.service('myService', ['$http', function($http) {
this.getData = function(){
// Simple GET request example:
return $http({
method: 'GET',
url: 'https://api.github.com/users/mralexgray/repos' // example API
}).then(function successCallback(response) {
return response;
}, function errorCallback(response) {
// return error message
});
}
}])
In your controller:
.controller('Controller2',['$scope','myService',function ($scope,myService) {
$scope.foo = myService.getData();
//resolve the promise:
$scope.foo.then(function(data){
console.log(data);
})
}
])
It is strongly recommended to use separated services as frishi pointed out. This sample is in single file and module just to make it readeable. Following implementation stores the promise and actual request is only made on the initial call to getFoo. The rest will get the response from the in memory promise.
'use strict';
angular.module('foo', [])
.factory('FooResource', function SessionResource($http) {
var fooPromise;
return {
getFoo: function getFoo() {
if(!fooPromise) {
fooPromise = $http.post('employee/fetchData?table=results');
}
return fooPromise;
}
};
})
.controller('FooController', function($scope, FooResource) {
FooResource.getFoo().then(function getFooSuccess(data) {
$scope.results = data;
});
});
I use this angular code with ionic framework
may be its help you..
my factory is..
angular.module('starter.services', [])
.factory('Chats', function() {
// Might use a resource here that returns a JSON array
// Some fake testing data
var chats = [{
id: 0,
name: 'Ben Sparrow',
lastText: 'You on your way?',
face: 'img/ben.png'
}, {
id: 1,
name: 'Max Lynx',
lastText: 'Hey, it\'s me',
face: 'img/max.png'
}, {
id: 2,
name: 'Adam Bradleyson',
lastText: 'I should buy a boat',
face: 'img/adam.jpg'
}, {
id: 3,
name: 'Perry Governor',
lastText: 'Look at my mukluks!',
face: 'img/perry.png'
}, {
id: 4,
name: 'Mike Harrington',
lastText: 'This is wicked good ice cream.',
face: 'img/mike.png'
}];
return {
all: function() {
return chats;
},
remove: function(chat) {
chats.splice(chats.indexOf(chat), 1);
},
get: function(chatId) {
for (var i = 0; i < chats.length; i++) {
if (chats[i].id === parseInt(chatId)) {
return chats[i];
}
}
return null;
}
};
});
and i use this factory in many controllers
.controller('ChatsCtrl', function($scope, Chats) {
$scope.chats = Chats.all();
$scope.remove = function(chat) {
Chats.remove(chat);
};
})
.controller('ChatDetailCtrl', function($scope, $stateParams, Chats) {
$scope.chat = Chats.get($stateParams.chatId);
})
in this code factory hit http:// request only one time and i use response on two controllers.
Hope its help you.
I am trying to implement this example to my project. you can see the front-end side code here.
this is my controller
(function(){
'use strict';
/* authentication Controllers */
var app = angular.module('pook');
app.controller('authCtrl',['$http','$rootScope', '$scope', '$location', '$localStorage', 'ngToast', 'Main', function($http, $scope, $location, $localStorage, ngToast, Main){
$scope.login = function(){
var formData = {
username: $scope.username,
password: $scope.password
};
Main.login(formData, function(res) {
if (res.type == false) {
alert(res.data)
} else {
$localStorage.token = res.data.token;
window.location = "/";
}
}, function() {
$rootScope.error = 'Failed to signin';
});
}
}]);
})();
below is my factory service
(function(){
'use strict';
var app = angular.module('pook')
app.factory('Main', ['$http', '$localStorage', function($http, $localStorage){
var baseUrl = "127.0.0.1:3000/api";
function changeUser(user) {
angular.extend(currentUser, user);
}
function urlBase64Decode(str) {
var output = str.replace('-', '+').replace('_', '/');
switch (output.length % 4) {
case 0:
break;
case 2:
output += '==';
break;
case 3:
output += '=';
break;
default:
throw 'Illegal base64url string!';
}
return window.atob(output);
}
function getUserFromToken() {
var token = $localStorage.token;
var user = {};
if (typeof token !== 'undefined') {
var encoded = token.split('.')[1];
user = JSON.parse(urlBase64Decode(encoded));
}
return user;
}
var currentUser = getUserFromToken();
return {
save: function(data, success, error) {
$http.post(baseUrl + '/users', data).success(success).error(error)
},
login: function(data, success, error) {
$http.post(baseUrl + '/login', data).success(success).error(error)
},
me: function(success, error) {
$http.get(baseUrl + '/me').success(success).error(error)
},
logout: function(success) {
changeUser({});
delete $localStorage.token;
success();
}
};
}
]);
})();
as you can see I copied and pasted from the example word by word and just changed the app name and controller name.
but I get this error below:
TypeError: Main.login is not a function
at Scope.$scope.login (http://127.0.0.1:3000/js/controllers/auth.js:15:12)
at $parseFunctionCall (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.js:12404:18)
at ngEventDirectives.(anonymous function).compile.element.on.callback (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.js:21566:17)
at Scope.$get.Scope.$eval (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.js:14466:28)
at Scope.$get.Scope.$apply (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.js:14565:23)
at HTMLFormElement.<anonymous> (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.js:21571:23)
at HTMLFormElement.jQuery.event.dispatch (https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.js:4435:9)
at HTMLFormElement.jQuery.event.add.elemData.handle (https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.js:4121:28)
I mean, There IS Main.login function. I don't see why it cant find it.
That is because Main is not what you think it is. When you use explicit dependency injection annotation you need to make sure order and number of dependecies and injected arguments are same.
.controller('authCtrl',
['$http','$rootScope', '$scope', '$location', '$localStorage', 'ngToast', 'Main',
^^^____
function($http, $scope, $location, $localStorage, ngToast, Main)
if you see you have an extra rootScope dependency injected to variable scope, so all the remaining arguments gets shifted. So Main variable actually holds $location object. When in doubt you can always reverify your argument list and do console logging. Proper indentation also helps in cases you have lots of arguments injected.
Remove $rootScope form the injection list and you should be fine.
I am trying to create an Angular Factory, this is based on a example from a plural site course http://www.pluralsight.com/training/player?author=shawn-wildermuth&name=site-building-m7&mode=live&clip=3&course=site-building-bootstrap-angularjs-ef-azure.
From debugging the code in Chrome it appears to run fine. I can see when I debug it that the service gets my data and puts it in my array but when I look at the controller in either $scope.data or dataService.data the arrays are empty. I don't see any javascript errors. I'm not sure what I'm doing wrong, any suggestions. I'm using AngularJS v1.3.15.
module.factory("dataService", function($http,$routeParams,$q) {
var _data = [];
var _getData = function () {
var deferred = $q.defer();
$http.get("/api/v1/myAPI?mainType=" + $routeParams.mainType + "&subType=" + $routeParams.subType)
.then(function (result) {
angular.copy(result.data,_data);
deferred.resolve();
},
function () {
//Error
deferred.reject();
});
return deferred.promise;
};
return {
data: _data,
getData: _getData
};});
module.controller('dataController', ['$scope', '$http', '$routeParams', 'dataService',function ($scope, $http, $routeParams, dataService) {
$scope.data = dataService;
$scope.dataReturned = true;
$scope.isBusy = true;
dataService.getData().then(function () {
if (dataService.data == 0)
$scope.dataReturned = false;
},
function () {
//Error
alert("could not load data");
})
.then(function () {
$scope.isBusy = false;
})}]);
On
return {
data: _data,
getData: _getData
};});
you have "data: _data," while your array is named just "data". Change the name of the variable to match and it will work:
var _data = [];
Why would you use deferred from $q this way?
The proper way to use $q:
$http.get("/api/v1/myAPI?mainType=" + $routeParams.mainType + "&subType=" + $routeParams.subType)
.success(function (result) {
deferred.resolve(result);
}).error(
function () {
//Error
deferred.reject();
});
And then in controller
dataService
.getData()
.then(function success(result) {
$scope.data = result; //assing retrived data to scope variable
},
function error() {
//Error
alert("could not load data");
});
In fact, there are some errors in your codes :
In your Service, you define var data = [];, but you return data: _data,. So you should correct the defination to var _data = []
you don't define _bling, but you use angular.copy(result.data,_bling);
One more question, why do you assigne the service to $scope.data : $scope.data = dataService ?
EDIT :
Notice that there 3 changes in the following codes:
comment the $scope.data = dataService;, because it makes no sense, and I think that $scope.data should be the data that the service returns.
$scope.data = dataService.data;, as I described in 1st point. You can see the result from the console.
In the if condition, I think that you want to compare the length of the returned data array, but not the data.
module.controller('dataController', ['$scope', '$http', '$routeParams', 'dataService',function ($scope, $http, $routeParams, dataService) {
// $scope.data = dataService;
$scope.dataReturned = true;
$scope.isBusy = true;
dataService.getData().then(function () {
if (dataService.data.length === 0){
$scope.dataReturned = false;
}else{
$scope.data = dataService.data;
console.log($scope.data);
}
},
// other codes...
})}]);