I have a angular service function that is being called multiple times.
In the index.html page I have the following line:
<li><i class="pull-right"></i><br/>{{appCtrl.service.getCurrentUser()}} </li>
In the application controller I set the variable
appCtrl.controller('AppController', function ($state, securityService, $log) {
$log.info('App controller');
var appCtrl = this;
appCtrl.service = securityService;
});
In my service I exposed the function
login.factory('securityService', function ($window, $log) {
var currentUser;
return {
setCurrentUser: function (user) {
currentUser = user;
$window.sessionStorage.setItem('User', JSON.stringify(currentUser));
},
getCurrentUser: function () {
$log.info('Calling current user');
if (!currentUser) {
var storedObject = $window.sessionStorage.getItem('User');
currentUser = JSON.parse(storedObject);
}
return currentUser;
}
}
});
The following line in the getCurrentUser function gets called multiple times when the application starts up or page refresh is being done.
$log.info('Calling current user');
The controller is being called only once, I monitor it by looking at $log.info('App controller');
Is it being called as part of the dirty checking process or am I doing something wrong?
Angular calls your function on every digest cycle, you can set breakpoint inside the function and check it. If you are on 1.3 version, then please take a look at One Time Binding feature. If not then call the service inside the controller and bind view to some scope variable:
$scope.currentUser = securityService.getCurrentUser();
And inside view bind to scope variable:
{{currentUser}}
Try this, this is correct factory declaration. Because internally AngularJS calls yout factory like: securityService(injects); , each time you inject (use) your factory.
login.factory('securityService', function ($window, $log) {
var currentUser;
return {
setCurrentUser: function (user) {
currentUser = user;
$window.sessionStorage.setItem('User', JSON.stringify(currentUser));
},
getCurrentUser: function () {
$log.info('Calling current user');
if (!currentUser) {
var storedObject = $window.sessionStorage.getItem('User');
currentUser = JSON.parse(storedObject);
}
return currentUser;
}
};
});
Related
I have a device service and a device controller. First, time whenever the controller is called, I invoke setter method to set a boolean value. I want to change that value when the logout function is called which is in different service.
My Device Service
define([], function () {
'use strict';
var DeviceService = [
"AuthService",
function (AuthService) {
var Device_Create = false;
return {
setUserCreatePermission :function () {
if(AuthService.checkForPermission('Device_Create')){
Device_Create = true;
}
},
getUserCreatePermission : function () {
return Device_Create
}
}
}];
return DeviceService;
})
My Device Controller has a init method which calls the setter method in device service. I have set a scope variable. If it set, it will call the method otherwise not.
define([], function () {
'use strict';
var DeviceListCtrl = ["$rootScope", "$scope", "DeviceService",
function ($rootScope, $scope, DeviceService) {
//variables
$scope.deviceList_init = true;
$scope.Device_Create = false;
init();
if(DeviceService.getDeviceCreatePermission()){
$scope.Device_Create = true;
}
function init() {
if($scope.deviceList_init){
DeviceService.setDeviceCreatePermission();
}
$scope.deviceList_init = false;
}
}]
return DeviceListCtrl;
});
Can someone help me ? TIA. I am new to this
I'm not sure I understood your problem but it seems that you are trying to control two different variables to do the same - one in the controller and other in the service.
If you want to have a variable across different controllers, it should be handled in services/factories.
If you want to notify other controllers that a variable has changed somewhere, you can use $rootScope.$broadcast or $scope.$broadcast depending if it is on the scope or not you need.
I've been struggling with this for a few days now and can't seem to find a solution.
I have a simple listing in my view, fetched from MongoDB and I want it to refresh whenever I call the delete or update function.
Although it seems simple that I should be able to call a previously declared function within the same scope, it just doesn't work.
I tried setting the getDispositivos on a third service, but then the Injection gets all messed up. Declaring the function simply as var function () {...} but it doesn't work as well.
Any help is appreciated.
Here's my code:
var myApp = angular.module('appDispositivos', []);
/* My service */
myApp.service('dispositivosService',
['$http',
function($http) {
//...
this.getDispositivos = function(response) {
$http.get('http://localhost:3000/dispositivos').then(response);
}
//...
}
]
);
myApp.controller('dispositivoController',
['$scope', 'dispositivosService',
function($scope, dispositivosService) {
//This fetches data from Mongo...
$scope.getDispositivos = function () {
dispositivosService.getDispositivos(function(response) {
$scope.dispositivos = response.data;
});
};
//... and on page load it fills in the list
$scope.getDispositivos();
$scope.addDispositivo = function() {
dispositivosService.addDispositivo($scope.dispositivo);
$scope.getDispositivos(); //it should reload the view here...
$scope.dispositivo = '';
};
$scope.removeDispositivo = function (id) {
dispositivosService.removerDispositivo(id);
$scope.getDispositivos(); //... here
};
$scope.editDispositivo = function (id) {
dispositivosService.editDispositivo(id);
$scope.getDispositivos(); //... and here.
};
}
]
);
On service
this.getDispositivos = function(response) {
return $http.get('http://localhost:3000/dispositivos');
}
on controller
$scope.addDispositivo = function() {
dispositivosService.addDispositivo($scope.dispositivo).then(function(){
$scope.getDispositivos(); //it should reload the view here...
$scope.dispositivo = '';
});
};
None of the solutions worked. Later on I found that the GET request does execute, asynchronously however. This means that it loads the data into $scope before the POST request has finished, thus not including the just-included new data.
The solution is to synchronize the tasks (somewhat like in multithread programming), using the $q module, and to work with deferred objects and promises. So, on my service
.factory('dispositivosService',
['$http', '$q',
function($http, $q) {
return {
getDispositivos: function (id) {
getDef = $q.defer();
$http.get('http://myUrlAddress'+id)
.success(function(response){
getDef.resolve(response);
})
.error(function () {
getDef.reject('Failed GET request');
});
return getDef.promise;
}
}
}
}
])
On my controller:
$scope.addDispositivo = function() {
dispositivosService.addDispositivo($scope.dispositivo)
.then(function(){
dispositivosService.getDispositivos()
.then(function(dispositivos){
$scope.dispositivos = dispositivos;
$scope.dispositivo = '';
})
});
};
Being my 'response' object a $q.defer type object, then I can tell Angular that the response is asynchronous, and .then(---).then(---); logic completes the tasks, as the asynchronous requests finish.
I'm having trouble setting $rootScope for Angularjs.
Below is my function
App.controller('Controller',
function (UtilityService, $rootScope) {
var setSession = function () {
$rootScope.test = "yes"; // <-- I get this
UtilityService.getSession().success(
function () {
$rootScope.test = "No"; // <-- I don't get this How do I get/set this value?
});
};
setSession();
});
Additional Info:
One of the ways that might work is to set up a service that is interacted between multiple controllers. Does anybody know how to do this with the service returning an http.get json object.
I'm having trouble getting a dynamic scope in my controller that is instantiated within a service.
In order to address my issue I had to
1) Pass $rootScope into my 2nd controller
App.controller($rootScope) {
2) Set my 2nd controller's function to $rootScope
$rootScope.functionCall = function () {};
3) Set my passed value to $rootScope ($rootScope.orderId)
$rootScope.functionCall = function () {
Service.getItems($rootScope.orderId).success(
function(results) {
$scope.items = results;
});
};
4) within my utility controller, I loop through my results, parsing them, and setting them to $rootScope as you can see in #3 I am initializing "$rootScope.orderId"
angular.forEach(results, function (value, key) {
if (key != null) {
$parse(key).assign($rootScope, value);
}
});
5) I am re-calling the controller's function from within my service call! This is what did the magic for me putting my variable "in scope"
$rootScope.functionCall();
6) I am also testing to see if the function exist cause different pages utilize the utility code but may not have the function to execute
if (typeof $rootScope.functionCall == 'function')
var setSession = function () {
UtilityService.getSession().success(
function (results) {
// Place the rootscope sessions in scope
angular.forEach(results, function (value, key) {
if (key != null) {
$parse(key).assign($rootScope, value);
}
});
// Have to bypass "scope" issues and thus have to execute these fns()
if (typeof $rootScope.functionCall == 'function') {
$rootScope.functionCall();
}
});
};
setSession();
As I wrote before I would use $scope when possible and if you need to share data across multiple controllers you can use a service. The code should be something like:
var app = angular.module('myApp', []);
app.factory('$http', 'myService', function ($http, myService) {
var customers = {};
$http.get("http://www.w3schools.com/website/Customers_JSON.php")
.success(function (response) {
customers = response;
});
return {
customers: customers
};
});
app.controller('controller_one', function($scope, myService) {
$scope.serv = myService.customers;
});
app.controller('controller_two', function($scope, myService) {
$scope.serv = myService.customers;
});
I need to show the name of current user in the top bar of my website. The user data should be disappeared when user logout. I used the following two services:
app.factory('Auth', ['$resource', function ($resource) {
return $resource('/user/login');
}])
.service('CurrentUser', [function () {
this.user= null;
}]);
Here is my login and topbar controllers.
app.controller('LoginCtrl', ['CurrentUser', 'Auth', '$location', function (CurrentUser, Auth, $location) {
this.login = function () {
var me = this;
me.user = Auth.save(me).$promise.then(
function (res) {
CurrentUser.user = res;
$location.path("/");
}, function (res) {
me.errors = res.data;
});
}
}])
.controller('TopBarCtrl', ['CurrentUser', function (CurrentUser) {
var me = this;
me.user = CurrentUser;
}])
Using this controllers and services in had to use {{contoller.user.user.name}} to show the user's name. Is there any way to use {{contoller.user.name}} instead and keep the two-way bindings?
You would have to use
me.user = CurrentUser.user;
As your are setting the result of your http.save in the first then to the .user property of CurrentUser.
What does the server result, e.g json, look like?
I have following code in angularjs .run()
so when the app is initial, I set 2 vars under rootScope.
Because these vars I decide to use in every routes (pages) and controllers.
async
app.run(function($rootScope, $timeout, firebaseAuth) {
$rootScope.$on('firebaseLoggedIn', function(event, authUser) {
$timeout(function() {
$rootScope._isLoggedIn = true;
$rootScope._authUser = authUser;
},0);
});
But the problem here, when I run it in my controllers, it always show undefined.
unless i put it in function block. So my guess is the controllers is run
before the .run() vars have value;
app.controller('foo', function($scope){
console.log($scope._authUser); //Always undefined
//unless I do following
//$scope.clickme = function() {console.log($scope._authUser)};
});
Any suggestion I am able to use the vars(async) from .run()?
If I call the following code in every controllers, it seems like I keep repeating myself.
$rootScope.$on('firebaseLoggedIn', function(event, authUser) {});
UPDATE
Here is where firebaseLoggedIn event from. I think I have to mention again. The callback is async.
app.service('firebaseAuth', ['$rootScope',
function($rootScope) {
//Define firebase DB url
this.firebaseRef = new Firebase("https://test.firebaseio.com");
this.onLoginStateChanges = new FirebaseAuthClient(this.firebaseRef, function(error, user) {
if (user) {
$rootScope.$emit("firebaseLoggedIn", user); //authenticated user
}
else if (error) {
$rootScope.$emit("firebaseLoginError", error); //authentication failed
}
else {
$rootScope.$emit("firebaseLogout"); //user not login
}
});
}]);
The run method will be ran when the injector is done loading all modules for your app. So your assumption about your controller being instantiated first is true.
What you're effectively doing with the $timeout(function() { ... },0) is forcing that code to run in the next digest loop. But I don't think this is what you're trying to accomplish anyway.
I'm not sure where 'firebaseLoggedIn' is being broadcasted from; but you may find this entire implementation would be more straight forward as an Angular Service.
app.service('FireBaseService', function($rootScope) {
// store these inside the service to be retrieved via methods below.
var isLoggedIn = false;
var authUser = {};
// let this be the only place you handle the LoggedIn event, setting user context.
$rootScope.$on('firebaseLoggedIn', function(event, authUser) {
isLoggedIn = true;
authUser = authUser;
});
// return some functions to expose the variables above
return {
getIsLoggedIn: function() {
return isLoggedIn;
},
getAuthUser: function() {
return authUser;
}
}
});
Then in your controller......
app.controller('foo', function($scope, $log, FireBaseService){
if (FireBaseService.getIsLoggedIn()){
$log.info(FireBaseService.getAuthUser().Name);
}
});
This enables you to have access to these variables anywhere you've injected the FireBaseService service.