I have an angular web application that is currently calling the backend API every time I need to display the user name or user image. However, I would now like to be able to cache this information in localStorage when the application is first started. What would be the best way or best place to do this in Angular? I image it would be something equivalent to the jquery $(document).ready method. Any hints would be appreciated.
You could put it in the run block. This will run once when your app starts up
angular.module('myApp').run(function () {
//Run init code
});
While you can use module.run for this, a better option would be a thematically related service. Angular services are created once, and so you can just put your loading code on the top level.
E.g.
angular.module('myApp').service('currentUser', function() {
// load user data from local storage, if not found load from server
// then store in localStorage
this.name = /* loaded name */;
// etc...
});
Note that most of requests are asynchronous, so you might want to do a factory that would return a user promise instead.
Related
i am using ionic 3 and i am trying to get value on the previous page but the constructor is not working, i also tried ionViewDidEnter(){} and
ionViewDidLoad(){}
i was moving my value through local storage and was calling it in the constructor and ionViewDidEnter(){}
ionViewDidLoad(){} of the previous previous page
this.locationvalue =localStorage.getItem('locationName')
console.log(this.locationvalue);
localStorage.removeItem('locationName');
I am using google chrome to application mode to read my localStorage and i am able to read my value there.
1) Perhaps have a look at NavParams as a better solution to local storage for this.
2) If not applicable because of multiple updates, I suspect if you are using local storage and you are NOT using a Promise with NavPop inside the then().
local storage service:
removeItem(...):Promise<any> {
return new Promise((resolve) =>{
...
}
}
nested page doing return:
goBack():void {
localStorage.removeItem('locationName').then(this.navCtrl.pop());
}
You have to realise the local storage update is asynchronous and does not block. So by the time you return to the prior page and render it, the local storage update, which I presume your returned to page is relying on to bind the data you display, will not have completed its update.
The underlying JavaScript Event Loop at the foundation of this.
Take a loop at this video.
3) Finally if you are confused by the Ionic Page lifecycle, this blog post may help too.
Let me know if this helps.
I'm building an app that needs to detect when a user loses internet connectivity or cannot reach the server. Multiple controllers and services need to be able to check and set this. I have achieved all of this with no problem using an angular service and
window.addEventListener('offline', function() {OfflineService.checkIfOnline});
then in the service with something like
window.navigator.onLine ? online = true : online = false
The tricky part comes in when I need to update the view when the offline event occurs. I can't seem to find a way to update the scope property or a controller property when the service property gets updated by the event.
When I use $scope.$watch, the function fires 10 times (noted by console.log) and then never again.
I tried to replicate the problem in a jsfiddle, but this is my first time using that tool, and I'm not sure if I did it right:
https://jsfiddle.net/m3nx5yLm/1/
Thank you for your help.
Thank you everyone for your help.
I ended up going with a solution suggested by a buddy of mine. Using $rootScope.$emit('offlineEvent' true); in the service and listening for it in the controller with $rootScope.$on('offlineEvent' this.setControllerProperty);.
https://jsfiddle.net/m3nx5yLm/3/
constructor($scope, OfflineNotificationService){
Looks like you were referencing the class from the scope not the instance created by the injector (needed to pass it in along with $scope). I also used the watch syntax where the first arg is a function just to be clear about making that call, the string syntax is typically just used to reference properties on scope. A few other notes you can just return the window.navigator.onLine and you can store the value on the service instance and reference it directly from the view, you can then call checkOnline periodically with a $timeout loop or listening for the online/offline events on the browser instead of using the watch to fire the function.
https://jsfiddle.net/m3nx5yLm/4/
I have an Angular2 app where user can log in and log out and I need to flush services data on log out, because they hold some data and backend subscriptions (websocket). Currently the only way I found is to reload the page after log out, but it's a crunchy solution. So, is there some convenient way to reinstantiate services (or remove the data they hold) in Angular2?
How about moving all your initialization logic to a method of that service, i.e init() then call that from the constructor when the application starts or on user logout.
EDIT
The short version:
Say I have application data is many different services. How do I get around needing to inject all of those services into every controller that displays application state?
EDIT
I am building my first Angular application. The basic design is I have a home page that shows the value of about 5 different variables (which are each pretty complicated). While on this page the app is collecting and analyzing data from bluetooth. Occasionally, the these 5 variables and some bluetooth data are saved to a REST back end and also saved to the device. There are pages for each of these 5 variables to change their value.
I have done my best to follow best practices. I have very thin controllers. I use services for all my data. I really only use $scope for binding data between views and controllers.
My issue now is that I started with a global "State" service to keep track of those 5 variables. I inject into any controller that needs to display state, and bind the html to it. Any time I want to change any state, I call a method of that State service to do it. This worked well, but now that State service is getting huge.
I have tried to break functions out to other services, but I run into the issue of needing to read data from the State service, then writing back to other properties of the State service. If I inject the other service into State, I can't inject State into the other service too.
I have thought about how I could have many smaller services, but I keep coming back to when I save the data to the server. When I do that I need to gather up data from every corner of the application to send up. If all this information is stored in different services, I am left with injecting all of them into a single service once again.
As I write this, I am pretty sure I am missing a big concept with using $scope across an application.
Any pointers would be appreciated,
Thanks,
Scott
Could you divide things into sub-services, and then make the State service an aggregator for these sub-services, then instead of injecting State into the sub-services, you inject the specific sub-service that you need? E.g.:
var app = angular.module('services', []);
app.service('sub1', function(){
return {
// ...
}
});
app.service('sub2', function(sub1){
var data = sub1.getData();
data.prop = 'new_value';
sub1.setData(data);
return {
// ...
}
});
app.service('State', function(sub1, sub2){
var data = sub1.getData();
data.prop = 'new_value';
sub1.setData(data);
var data = sub2.getData();
data.prop = 'new_value';
sub2.setData(data);
return {
// ...
}
});
Looks like you need Redux to help you manage your application state
https://github.com/wbuchwalter/ng-redux
In my AngularJS application, I have a Session service object that contains stuff like the current user, their preferences, the current company they belong to, and the current theme that they are using. Many places in my application refer to the Session service when they need to get at this data.
Because these variables are in a service, I cannot use scope watches to detect changes. So instead, I've decided to use the observer pattern. Various places in the application, such as other services, directives, controllers, etc. will register themselves with the Session service and provide a callback to be executed whenever the Session changes.
For example, if the user changes their theme, the <style> element in index.html that uses a custom directive will be notified, and it will recreate all of the overriding css rules for the new colors.
For another example, whenever the user's avatar is updated, the main menu bar controller will be notified to refresh and redraw the avatar. Stuff like this.
Obviously the data in Session has to be refreshed at least once before the various controllers, directives, etc. use it. The natural place to ask the Session service to get its session data was in a run block for the application-level module. This works pretty well, but I don't think it's the best place either.
One problem I have noticed is that when Firebug is open, the asynchronous nature of things loading causes ordering issues. For example, the directive that runs on the <style> element will run AFTER the Session service has refreshed in the application's run block... which means the theme will not get updated after pressing F5 because the callback is registered after the initialization of the data occured. I would have to call a manual refresh here to keep it in sync, but if I did that, it may execute twice in the times where the order is different! This is a big problem. I don't think this issue is just related to Firebug... it could happen under any circumstance, but Firebug seems to cause it somewhat consistently, and this is bad.
To recap... This asynchronous ordering is good:
Theme Directive registers callback to Session
Menu Bar application controller registers callback to Session
Session.refresh() is called in .run block.
This asynchronous ordering is bad:
Menu Bar application controller registers callback to Session
Session.refresh() is called in .run block.
Theme Directive registers callback to Session, but callback does not get executed since Session.refresh() was already executed.
So rather than use the observer pattern, or refresh the Session state via a run block, what the best way to design the services, etc. so that the session data will ALWAYS get refreshed after (or maybe before) the various other parts of the application require it? Is there some kind of event I can hook into that gets executed before directives and controllers are executed instead of the run block?
If my approach is generally sound, what can I add to it to really make it work the way it should?
Thanks!
In angular.js you have 2 way of using global variables:
use a $rootScope
use a service
Using $rootScope is very easy as you can simply inject it into any controller and change values in this scope. All global variables have problems!
Services is a singletons(What you need)!
I think in your case you can use
$rootScope
And
$scope.$watch
Great answer
Is there a reason you can't access the variables directly like this:
app.factory('SessionService', function() {
var items = {
"avatar": "some url"
};
return items;
});
var MainController = [$scope, 'SessionService', function($scope, SessionService){
$scope.session = SessionService;
$scope.modifyAvatar = function(url){
$scope.session.avatar = "some new url";
};
}];
var HeaderController = [$scope, 'SessionService', function($scope, SessionService){
$scope.session = SessionService;
// You probably wouldn't do this, you would just bind
// to {{session.avatar}} in your template
$scope.getAvatar = function(){
return $scope.session.avatar;
};
}];