I am trying to retrieve my search and filter data from sessionStorage when the page refreshes.
sessionStorage.restorestate returns undefined, does anyone know why?
app.run(function($rootScope) {
$rootScope.$on("$routeChangeStart", function(event, next, current) {
if (sessionStorage.restorestate == "true") {
$rootScope.$broadcast('restorestate'); //let everything know we need to restore state
sessionStorage.restorestate = false;
}
});
//let everthing know that we need to save state now.
window.onbeforeunload = function(event) {
$rootScope.$broadcast('savestate');
};
});
Plunkr: http://plnkr.co/edit/oX4zygwB0bDpIcmGFgYr?p=preview
When you refresh the page in an Angular app, it is like completely rebooting the application. So to restore from the session storage, just do it when the service factory executes.
app.factory('CustomerSearchService', ['$rootScope',
function($rootScope) {
...
function restoreState() {
service.state = angular.fromJson(sessionStorage.CustomerSearchService);
}
if (sessionStorage.CustomerSearchService) restoreState();
...
}
]);
The saving part was already correct.
app.factory('CustomerSearchService', ['$rootScope',
function($rootScope) {
...
function saveState() {
sessionStorage.CustomerSearchService = angular.toJson(service.state);
}
$rootScope.$on("savestate", saveState);
...
}
]);
app.run(function($rootScope) {
window.onbeforeunload = function(event) {
$rootScope.$broadcast('savestate');
};
});
DEMO
Related
I did this below to detect back button hit to previous page, but the detection is working fine, my headache is that the app run functions variable $rootScope.UseInController don't pass the data once to controller.
Here is the script.
App.run(function($rootScope, $location, $route, $localStorage){
$rootScope.$on('$locationChangeStart', function() {
$rootScope.$on('$locationChangeSuccess', function() {
// Check if you've been here before.
$rootScope.actualLocation = $location.path();
});
});
$rootScope.$watch(
function() {
return $location.path();
},
function(newLocation, oldLocation){
if($rootScope.actualLocation === newLocation) {
$rootScope.backClicked = true;
}
},true);
})
Please help me out....
This is what i finally does and make it worked perfectly, i delay my controller a bit.
$timeout(function(){..}, 5);
I'm learning RxJS and am trying to implement it in one of my existing applications. First thing I am trying to do is remove rootscope.broadcast/emit methods and replace them with BehaviorSubjects. This has worked fine if those events are subscribed to inside a controller. However, if I try to subscribe to those events in a service, they never fire. I can move the exact same subscription into a component/controller/etc and it works fine.
Is there a reason for this or should I be able to do this and I am just doing something wrong?
UPDATE 1
I have an event service that maintains events run at the top of the application like so:
(function () {
"use strict";
angular.module("app.common").service("eventService", EventService);
function EventService($window) {
"ngInject";
var defaultBehaviorSubjectValue = null;
var service = {
activate: activate,
onLogin: new Rx.BehaviorSubject(defaultBehaviorSubjectValue), //onnext by authService.login
onLogout: new Rx.BehaviorSubject(defaultBehaviorSubjectValue), //onnext by authService.logout
isOnline: new Rx.BehaviorSubject(defaultBehaviorSubjectValue) //onnext by authService.logout
};
return service;
function activate() {
service.onLogin.subscribe(function (userData) {
console.info("user logged in");
});
service.onLogout.subscribe(function (userData) {
console.info("Logging user out");
dispose();
});
$window.addEventListener("offline", function () {
console.info("Lost internet connection, going offline");
service.isOnline.onNext(false);
}, false);
$window.addEventListener("online", function () {
console.info("Regained internet connection, going online");
service.isOnline.onNext(true);
}, false);
}
function dispose() {
angular.forEach(service, function (event, index) {
if (service && service[event] && service[event].isDisposed === false) {
service[event]();
}
});
}
}
})();
I have a service that is waiting for that onLogin event to fire. The code is simliar to:
(function () {
angular.module("app.data").service("offlineProjectDataService", OfflineProjectDataService);
function OfflineProjectDataService(definitions, metaDataService, userService, eventService) {
"ngInject";
var onLoginSubscription = eventService.onLogin.subscribe(function (isLoaded) {
if (isLoaded) {
activate();
}
});
var service = {
activate: activate
}
return service;
function activate(){
//..some stuff
}
}
})();
The problem I'm having is that the onLogin event is not firing so my activate method is not being called. If I move that exact same subscription line to some other controller in my app, it DOES fire. So I don't think there is anything wrong with syntax.
Unless of course I'm missing something here that is probably painfully obvious to somebody.
Use RxJS in a Service
Build a service with RxJS Extensions for Angular.
<script src="//unpkg.com/angular/angular.js"></script>
<script src="//unpkg.com/rx/dist/rx.all.js"></script>
<script src="//unpkg.com/rx-angular/dist/rx.angular.js"></script>
var app = angular.module('myApp', ['rx']);
app.factory("DataService", function(rx) {
var subject = new rx.Subject();
var data = "Initial";
return {
set: function set(d){
data = d;
subject.onNext(d);
},
get: function get() {
return data;
},
subscribe: function (o) {
return subject.subscribe(o);
}
};
});
Then simply subscribe to the changes.
app.controller('displayCtrl', function(DataService) {
var $ctrl = this;
$ctrl.data = DataService.get();
var subscription = DataService.subscribe(function onNext(d) {
$ctrl.data = d;
});
this.$onDestroy = function() {
subscription.dispose();
};
});
Clients can subscribe to changes with DataService.subscribe and producers can push changes with DataService.set.
The DEMO on PLNKR.
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 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.
I am using firebase simple login auth with angularjs and I want to create a single page app.
Before this, I have tried using service, main controller to handle it but I don't think it is good enough because I have to call FirebaseAuthClient() every time there is a route.
I also try to put FirebaseAuthClient() in angularjs .run() which initialize when app is start.
But it won't work when there is a route, I think it is because not a full page load.
Ok,
And here is what I want,
except login page, every route (pages) are required login.
A global FirebaseAuthClient() checking on every route so I don't need to call it again.
A global user which return from FirebaseAuthClient()
I'm not sure I understand. You only need to initialize FirebaseAuthClient and all login() once in your entire app. It's a singleton, and your auth credentials apply to any Firebase operations you perform.
What makes you think that this is not the case? What sorts of errors are you seeing?
Here is what I was using before moving auth over to Singly. Maybe it helps?
p4pApp.factory('firebaseAuth', function($rootScope) {
var auth = {},
FBref = new Firebase(p4pApp.FIREBASEPATH);
auth.broadcastAuthEvent = function() {
$rootScope.$broadcast('authEvent');
};
auth.client = new FirebaseAuthClient(FBref, function(error, user) {
if (error) {
} else if (user) {
auth.user = user;
auth.broadcastAuthEvent();
} else {
auth.user = null;
auth.broadcastAuthEvent();
}
});
auth.login = function() {
this.client.login('facebook');
};
auth.logout = function() {
this.client.logout();
};
return auth;
});
The AuthCtrl is common to all/most of my pages.
var AuthCtrl = function($scope, firebaseAuth) {
$scope.login = function() {
firebaseAuth.login();
};
$scope.logout = function() {
firebaseAuth.logout();
};
$scope.isLoggedIn = function() {
return !!$scope.user;
};
// src: Alex Vanston (https://coderwall.com/p/ngisma)
$scope.safeApply = function(fn) {
var phase = this.$root.$$phase;
if (phase == '$apply' || phase == '$digest') {
if(fn && (typeof(fn) === 'function')) {
fn();
}
} else {
this.$apply(fn);
}
};
$scope.$on('authEvent', function() {
$scope.safeApply(function() {
$scope.user = firebaseAuth.user;
});
});
};
From within the AuthCtrl you can just call isLoggedIn() to see if the user is logged in or not.