Passing Data Between Pages in AngularJS + Page Refresh - angularjs

I am trying to pass data between pages in the checkout process of an app but it's not working the way it should. I have done some reading and most people recommend using a service, but the only issue is that when the page is refreshed (user clicks refresh or comes back at a later time) all the data from the service disappears. This makes sense since the data in a service is not meant to be persistent but it is causing a problem.
So the question is: how can I pass data between pages in angularJS and still keep the data that was passed after a page refresh?
Here is my code so far (with my attempt at using query strings):
.service('checkoutService',
function checkoutService($location, Address, $routeParams, TicketGroup) {
var ticket_quantity = 0;
var ticket_group = {};
var selected_address = {};
this.loadInformation = function() {
if(!ticket_quantity && $routeParams.ticket_quantity)
ticket_quantity = $routeParams.ticket_quantity;
if(!ticket_group && $routeParams.ticket_group_id)
ticket_group = TicketGroup.get({id: $routeParams.ticket_group_id});
if(!selected_address && $routeParams.address_id)
selected_address = Address.get({id: $routeParams.address_id});
}
this.setTicketQuantity = function(quantity) {
ticket_quantity = quantity;
$location.path().search({ticket_quantity: quantity});
}
this.getTicketQuantity = function() {
return ticket_quantity;
}
this.setTicketGroup = function(object) {
ticket_group = object;
$routeParams.ticket_group = object.id;
}
this.getTicketGroup = function() {
return ticket_group;
}
this.setSelectedAddress = function(object) {
selected_address = object;
$routeParams.address_id = object.id;
}
this.getSelectedAddress = function() {
return selected_address;
}
});

There are several options to do this,
For smaller data sets you could use the $cookieStore, for data that is under 4k
Another option, especially with large data sets, would be to use Local Storage and then retrieve the data on page load/reload.
if it is only a very small amount of data, or data that is used through out multiple page you could use $rootscope, but this is not the best option as it just like polluting the global name space.
The last option, depending on how the data is retrieved, a service could be implemented, that is basically a singleton that can be passed to various angular scope.
Note: only the first two are persistent.
In your case I think that using local storage or the cookiestore will be you best options. You are trying to use a service, which would be appropriate if you did not want it to be persistent (leaving the page or a page refresh). Services are singletons that being managed by angular, when injected you will get a reference to the same object in each injection. However, when returning to the page this singleton will need to be re initialized, thus losing all previous data. The only way to make make a service persistent would be to load the data from a database, a local file, or noSQL from elsewhere. However, I do not think this is really what you are after.
If you are interested in pursuing the local storage implementation then look into these modules angular-local-storage, ngStorage or this answer
If you want to use the cookiestore look into this answer

You can use Session/LocalStorage. Or a browser db like pounchdb.
Seesion storage: store session data;
LocalStorage: store data not just session scope
pounchdb : offline db

Related

Local Forage and Angular - issue with Get Item from Local Storage

I have an angular model named rows.
I have a piece of code that tries to fetch data from local storage using LocalForage and set the local data to the rows model.
Apparently, it seems like, by the time the local storage call back for get item executes, the $scope.rows model goes out of scope.
Is there a way, i can achieve this, that is set the value from local storage to the rows model?
localforage.getItem(localBlogKey, function (err, readValue)
{
if (readValue !== null && readValue !== undefined)
{
var localdata = readValue.data;
$scope.rows = angular.fromJson(localData);
}
});
Since this piece of code runs asynchronously, the $scope.rows goes out of scope? Is there a sunchronous way to pull data from localforage?
This is achieved using the ngStorage Module.
Import the ngStorage module and then access the localstorage item with the key as below
localstorage.myKey = "myValue";
This is Synchronous and hence my issue is resolved.

Angular - reusing code (service or controller)

I'm using Angular to develop commenting functionality for a web app.
Currently there are two sections in the application were a user can comment:
Category
Product
About 90% of the commenting functionality is the same for both sections and as such I would like to make this reusable - i.e write some service or controller that I can reference/use as a base.
So far, my research seems to point to using a factory service but unfortunately this doesn't seem to work (I've spent the whole day running through various tutorials).
It is quite possible that I am over thinking this and making it far too complicated but I honestly don't know which way to turn anymore.
Herewith a quick and dirty overview of what I have so far:
HTML view for the category
Controller for the category (receives data from service and posts data to service in order to bind data to model)
Service for the category (retrieve and stores all the necessary
data)
The product uses the same logic and a lot of the code in the service and controller will be duplicated.
I've merged the two services into one service successfully but I'm having trouble doing the same for the controller.
Do I:
Write a base controller that will communicate with the above mentioned service and that will hookup with the two existing controllers
OR
Write a factory/provider service that hooks up to the two existing controllers as well as the above mentioned service.
If you go the route of using a factory, you could put all the common functionality into its return object and reference that from your controllers.
Factory
angular.module('myModule').factory('CommonFunctions', function(){
return {
foo : foo,
bar : bar
}
function foo(){
console.log('foo');
};
function bar (){
console.log('bar');
};
}
Controller
angular.module('myModule')
.controller('myController', ['CommonFunctions', function(CommonFunctions) {
var vm = this;
vm.foo = CommonFunctions.foo();
vm.bar = CommonFunctions.bar();
}
angular's separation of service types ie:
for specific values
constant
value
(constant for specific values needed before other services are created)
for functions
factory
service
provider
(provider for specific instances when you need a services before other services are created, usually taking advantage of constants)
allow the ability to share data and ways to process that data between controllers and or directives, anything that can be a value can also be a constant, the only difference there being where they can be injected. Similarly any service can be rewritten to a factory or a provider, it is more your specific use case / what your more comfortable writing that would determine which to use, but really the best way to think about it is if you have a value that needs to be shared but is not needed inside angular.module.config then use value, otherwise use constant, now if you have a single function that you want to share, (maybe it processes that value in some way or maybe it just does something else) you should write it as a factory, then when you have a few of those factory's that deal with either that value, or anything else, you can combine them into a service or configure and combine them using a provider. here is a simple example (note i am using the recommended syntax for writing angular services):
'use strict';
var app = angular.module('test.app',[]);
app.constant('configureableValue',{defaultValue:55});
app.value('editableValue',{defaultValue:100,editedValue:null});
app.provider('configureValue',configureValueProvider);
configureValueProvider.$inject - ['configureableValue'];
function configureValueProvider(configureableValue){
var defaultVal = configureableValue.defaultValue,
originalVal = defaultVal;
return {
getValue:getValue,
setValue:setValue,
resetValue:resetValue,
'$get':providerFunc
};
function getValue(){
return defaultVal;
}
function setValue(val){
defaultVal = val;
}
function providerFunc(){
return {
get:function(){ return getValue(); },
reset:function(){ resetValue(); }
};
}
function resetValue(){
defaultVal = originalVal
}
}
// this factory is an example of a single function service, this should almost always be defined as a factory
app.factory('getEditableValue',getEditableValue);
getEditableValue.$inject = ['editableValue'];
function getEditableValue(editableValue){
return function(){
return editableValue.editedValue ? editableValue.editedValue : editableValue.defaultValue;
};
}
// same with this one
app.factory('setEditableValue',setEditableValue);
setEditableValue.$inject = ['editableValue'];
function setEditableValue(editableValue){
return function(val){
editableValue.editedValue = val;
}
}
// now this is an example of a service service collecting the factorys for an object with all the related behavior we need
app.service('editableService',editableService);
editableService.$inject = ['getEditableValue','setEditableValue'];
function editableService(getEditableValue,setEditableValue){
var self = this;
self.setVal = setEditableValue;
self.getVal = getEditableValue;
}
app.config(appConfig);
appConfig.$inject = ['configureValueProvider'];
function appConfig(configureValueProvider){
configureValueProvider.setValue('i changed '+ configureValueProvider.getValue() +' to this!!!!');
}
app.run(appRun);
appRun.$inject = ['configureValue','editableService'];
function appRun(configureValue,editableService){
console.log('before editing: ',editableService.getVal());
editableService.setVal('changed!!!');
console.log('after editing: ',editableService.getVal());
console.log('we changed this in the config func: ',configureValue.get());
configureValue.reset();
console.log('and now its back to the original value: ',configureValue.get());
}
i know thats a lot for a simple example, but there are a lot of features provided by angular, and many ways to use them, hopefully this helps.

How to handle user model in an AngularJS application?

I am refactoring an AngularJS application, and there, almost everything is stored in the $rootScope.
In my old applications I've build with Angular, I created a Service for each model, and then instantiated it within a Controller when needed.
I ask myself: Is it ok to store the whole user object inside the
$rootScope or what is best practice here?
How can I get sure to create a user during login and then pass it around throughout the whole application?
It seems ok generally storing user like models in $rootScope. But In my opinion it's not a best practise in angularjs(However I have used $rootScope way before).
Factory is the one of angularjs' beauty. Generally we use it to call rest services. But also you can create a model with it. Also you will be able to extend your model easily with injecting another model. That's just an idea , may be there is another better options to use model like objects in angularjs.
Lets look an example
// User Model
app.factory('User', function() {
var User = function(username) {
this.username = username;
this.email = null;
};
User.prototype.getDetails = function() {
var self = this;
return self.username;
};
return User;
});
// ExtendedUser Model
app.factory('ExtendedUser', function(User) {
var ExtendedUser = function() {
User.apply(this, arguments);
};
ExtendedUser.prototype = new User();
function getEmail() {
var self = this;
// You can make an http call to get email like information as an extra
self.email = "email#email.com";
return self;
}
ExtendedUser.prototype.getDetails = function() {
var self = this;
var extendedUser = getEmail();
return extendedUser;
};
return ExtendedUser;
});
I would look into a0-angular-storage: https://github.com/auth0/angular-storage It is great for storing user information / tokens or whatever to be retrieved throughout your app.
Key Features
Uses localStorage or sessionStorage by default but if it's not available, it uses ngCookies.
Lets you save JS Objects, If you save a Number, you get a Number, not a String
Uses a caching system so that if you already have a value, it won't get it from the store again.
If you don't want to store user model in $rootScope you can use private JS variable, which can be accessed by some service in Angular(since both factory and a service are singleton in Angular).
The nice addition is that it is harder to determine where the user model is stored, the only thing you need is proper encapsulation and code structure.

Best way to keep and share huge data between controllers

The App I'm building is complex and the data is huge. It is an order administration dispatch app.
At the beginning the first thing I have to do it to get from the API all the orders, all the stores and all the couriers.
During the life cycle of an order I receive several updates from the API and I handle everything through Server Sent Events.
Once I load the data I put everything in 3 different $scope: $scope.orders, $scope.stores and $scope.couriers and a I created a service to handle and share updated data between controllers.
One of the service look like this:
App.factory('Orders', ['logs', function (logs) {
var orders = {};
var newOrder = null;
var updatedOrder = null;
orders.list = [];
orders.getNewOrder = function () {
return newOrder;
};
orders.setNewOrder = function (order) {
newOrder = order;
};
orders.updateOneOrder = function (index, order) {
orders.list[index] = order;
updatedOrder = order;
};
orders.getUpdatedOrder = function () {
return updatedOrder;
};
orders.getAllOrders = function () {
return orders.list;
};
return orders;
}]);
And I $watch for those methods to see changes and update the relative $scope.
As you can see in my service I have one more Array to store data in order to be able to handle it due to the fact I can not use $scope in a Factory.
I followed a guide online regarding this. I know there is also Broadcast and Emit but probably it was too complex to handle all those things with that method.
One more thing I avoided is to store orders, stores and couriers in $rootScope.
I think the App is a bit slow and use a lot of memory to handle everything so I wish to know the best practice to handle huge data that need to be shared between controllers and updated in real time...
I think my method at the moment is using too much memory.

Passing data to another page using AngularJs

I am trying to pass data from one page to another using AngularJs service but whatever value I set in the variables in the service on one page, it is lost on redirection. Is there any particular way to perform the redirection? Below is the flow of my code
//Created a service to pass data
angular.module('Test').service('TestService', function() {
var new_data;
this.addData = function(page_data) {
new_data = page_data;
}
this.getData = function(){
return new_data;
}
});
//Code in controller A:
TestService.addData(data);
$window.location.href = "/static/html/buyer-cart-confirmation.html"
//Code in controller B:
data = TestService.getData();
No data is received in controller B. Can somebody please help me with this.
Thank you!
You can use session storage to serialize / deserialize data across different instances of angular within the same session (tab), and you can use local storage to do the same thing across sessions, (new tab). Here is the code for both:
Session Storage
class SessionStorageService
setStorage:(key, value) ->
json = if value? then JSON.stringify value else null
sessionStorage.setItem key, json
getStorage:(key)->
JSON.parse sessionStorage.getItem key
pageData1:(value=null) ->
#accessor 'pageData1', value
pageData2:(value=null) ->
#accessor 'pageData2', value
# more data values defined here
accessor:(name, value)->
return #getStorage name unless value?
#setStorage name, value
angular
.module 'app.Services'
.service 'sessionStorageService', SessionStorageService
Local Storage Service
class LocalStorageService
setStorage:(key, value) ->
json = if value? then JSON.stringify value else null
localStorage.setItem key, json
getStorage:(key)->
JSON.parse localStorage.getItem key
clear: ->
#setStorage(key, null) for key of localStorage
pageData1:(value=null) ->
#accessor 'pageData1', value
pageData2:(value=null) ->
#accessor 'pageData2', value
# more data values defined here
accessor:(name, value)->
return #getStorage name unless value?
#setStorage name, value
angular
.module 'app.Services'
.service 'localStorageService', LocalStorageService
With that said, you need to ask yourself why you are redirecting to a different page with any expectation that your state will somehow be preserved?
Angular is typically used for Single Page Applications that use routing frameworks like ui-router to manage state transformations, rather than the old-school, click-and-refresh-the-page model.
In other words, you should not redirect unless you intend on starting a brand new Angular application.
I think your logic is wrong, and since you don't provide a Plunker I can't test it at the moment. I think you should go with smth like:
angular.module('Test').service('TestService', function() {
this.addData = function(page_data) {
this.new_data = page_data;
};
return this;
});
and then you access your data like this:
TestService.new_data
I think it will work like this.

Resources