I develop a mobile application using ionic. when I load a page ( using window.location.reload(); in javascript ) the application lose the information of the user (the information of authentification ) .
I m looking for a solution that allow my app to save these information even I load the page !
I use this service inside my app.js to save the data of the user and share it with controllers
.service('sharedProperties', function () {
var idpersonne,nom,prenom,login,pass,admin ;
return {
getIdpersonne: function () {
return idpersonne;
},
setIdpersonne: function(value) {
idpersonne = value;
},
getNom: function () {
return nom;
},
setNom: function(value) {
nom = value;
},
getPrenom: function () {
return prenom;
},
setPrenom: function(value) {
prenom = value;
},
getLogin: function () {
return login;
},
setLogin: function(value) {
login = value;
},
getPass: function () {
return pass;
},
setPass: function(value) {
pass = value;
},
getAdmin: function () {
return admin;
},
setAdmin: function(value) {
admin = value;
}
};
})
I suggest you to take a look into the local storage to save data easily (http://learn.ionicframework.com/formulas/localstorage/).
This article from Ionic team shows everything in details.
The basic syntax for the local storage is:
window.localStorage['name'] = 'Max';
and load the value by:
var name = window.localStorage['name'] || 'you';
Related
I work over a small React app that should store some data in local storage. And if I understand it correctly, it should keep them till clearly ordered to clear. The reason for this post is that while app data perfectly survives the refreshing page action, it disappears after closing/opening Chrome.
Here is the function which creates the storage:
export function initGlobalStorage() {
var Storage = function (options) {
options = options || {};
for (var i in options) {
this[i] = options[i];
}
};
const prefix = window.location.href;
Storage.prototype = {
storage: window.localStorage,
addPrefix: function(key){return (prefix + key); },
set: function (key, value) {
this.storage.setItem(this.addPrefix(key), JSON.stringify(value));
},
get: function (key) {
return this.storage.getItem(this.addPrefix(key));
},
remove: function (key, value) {
this.storage.remove(key, value);
},
clear: function () {
this.storage.clear();
},
key: function (index) {
return this.storage.key(index);
},
each: function (fn) {
if (typeof fn === "function") {
for (var i = 0, key; i < this.storage.length; ++i) {
key = this.storage.key(i);
fn(this.storage.getItem(key), key, i);
}
}
},
getAll:function(){
let result =[];
for(var key in this.storage){
if (key.includes(prefix)){result.push(JSON.parse(this.storage.getItem(key)))};
}
return result;
},
hasItems:function(){
console.log(this.getAll().length);
return this.getAll().length? true:false;
},
};
window.Storage = {
local: new Storage({ storage: window.localStorage }),
session: new Storage({ storage: window.sessionStorage }),
};
};
window.local.href is for distinguish 'my items' in localStorage from others that possibly exists there on client computer. BTW, currently I only test this app on localhost.
Here is how above function is applied
export function checkSupportForCache() {
return dispatch => {
if (storageAvailable('localStorage')) {
dispatch(cacheSupported());
console.warn("Storage available");
initGlobalStorage();
if (window.Storage.local.hasItems()){
console.log('Storage contains items');
dispatch(cacheNotEmpty());
}else{
console.warn("No items in storage");
}
} else {
console.warn("Storage not available");
}
};
}
storageAvailable('localStorage') is a function that checks support for localStorage in a certain browser.
As I have written, when I refresh page localStorage is still there - then I suppose code is OK.
But what happens when do close browser then? I do not consciously request for any sort of purging action. Do I unconsciously? I have checked Chrome settings and there is nothing that looks suspicious. Do I not understand anything at all as per subject? Maybe, just give me a hint.
I'm new to VueJs and currently trying to load some data only once and make it globally available to all vue components. What would be the best way to achieve this?
I'm a little bit stuck because the global variables occasionally seem to become null and I can't figure out why.
In my main.js I make three global Vue instance variables:
let globalData = new Vue({
data: {
$serviceDiscoveryUrl: 'http://localhost:40000/api/v1',
$serviceCollection: null,
$clientConfiguration: null
}
});
Vue.mixin({
computed: {
$serviceDiscoveryUrl: {
get: function () { return globalData.$data.$serviceDiscoveryUrl },
set: function (newUrl) { globalData.$data.$serviceDiscoveryUrl = newUrl; }
},
$serviceCollection: {
get: function () { return globalData.$data.$serviceCollection },
set: function (newCollection) { globalData.$data.$serviceCollection = newCollection; }
},
$clientConfiguration: {
get: function () { return globalData.$data.$clientConfiguration },
set: function (newConfiguration) { globalData.$data.$clientConfiguration = newConfiguration; }
}
}
})
and in my App.vue component I load all the data:
<script>
export default {
name: 'app',
data: function () {
return {
isLoading: true,
isError: false
};
},
methods: {
loadAllData: function () {
this.$axios.get(this.$serviceDiscoveryUrl)
.then(
response => {
this.$serviceCollection = response.data;
let configurationService = this.$serviceCollection.services.find(obj => obj.key == "ProcessConfigurationService");
this.$axios.get(configurationService.address + "/api/v1/clientConfiguration").then(
response2 => {
this.$clientConfiguration = response2.data;
}
);
this.isLoading = false;
})
}
},
created: function m() {
this.loadAllData();
}
}
</script>
But when I try to access the $clientConfiguration it seems to be null from time to time and I can't figure out why. For example when I try to build the navigation sidebar:
beforeMount: function () {
let $ = JQuery;
let clients = [];
if (this.$clientConfiguration === null)
console.error("client config is <null>");
$.each(this.$clientConfiguration, function (key, clientValue) {
let processes = [];
$.each(clientValue.processConfigurations, function (k, processValue) {
processes.push(
{
name: processValue.name,
url: '/process/' + processValue.id,
icon: 'fal fa-project-diagram'
});
});
clients.push(
{
name: clientValue.name,
url: '/client/' + clientValue.id,
icon: 'fal fa-building',
children: processes
});
});
this.nav.find(obj => obj.name == 'Processes').children = clients;
The most likely cause is that the null is just the initial value. Loading the data is asynchronous so you'll need to wait for loading to finish before trying to create any components that rely on that data.
You have an isLoading flag, which I would guess is your attempt to wait for loading to complete before showing any components (maybe via a suitable v-if). However, it currently only waits for the first request and not the second. So this:
this.$axios.get(configurationService.address + "/api/v1/clientConfiguration").then(
response2 => {
this.$clientConfiguration = response2.data;
}
);
this.isLoading = false;
would need to be:
this.$axios.get(configurationService.address + "/api/v1/clientConfiguration").then(
response2 => {
this.$clientConfiguration = response2.data;
this.isLoading = false;
}
);
If it isn't that initial value that's the problem then you need to figure out what is setting it to null. That should be prety easy, just put a debugger statement in your setter:
$clientConfiguration: {
get: function () { return globalData.$data.$clientConfiguration },
set: function (newConfiguration) {
if (!newConfiguration) {
debugger;
}
globalData.$data.$clientConfiguration = newConfiguration;
}
}
Beyond the problem with the null, if you're using Vue 2.6+ I would suggest taking a look at Vue.observable, which is a simpler way of creating a reactive object than creating a new Vue instance.
Personally I would probably implement all of this by putting a reactive object on Vue.prototype rather than using a global mixin. That assumes that you even need the object to be reactive, if you don't then this is all somewhat more complicated than it needs to be.
Here is my service
angular.module('starter.services').factory('PaypalService', function ($q, $ionicPlatform, shopSettings, $filter, $timeout) {
var init_defer;
var service = {
initPaymentUI: initPaymentUI,
createPayment: createPayment,
configuration: configuration,
onPayPalMobileInit: onPayPalMobileInit,
makePayment: makePayment
};
return service;
function initPaymentUI() {
init_defer = $q.defer();
$ionicPlatform.ready().then(function () {
var clientIDs = {
"PayPalEnvironmentProduction": shopSettings.payPalProductionId,
"PayPalEnvironmentSandbox": shopSettings.payPalSandboxId
};
PayPalMobile.init(clientIDs, onPayPalMobileInit);
});
return init_defer.promise;
}
function createPayment(total, name) {
// "Sale == > immediate payment
// "Auth" for payment authorization only, to be captured separately at a later time.
// "Order" for taking an order, with authorization and capture to be done separately at a later time.
var payment = new PayPalPayment("" + total, "USD", "" + name, "Sale");
return payment;
}
function configuration() {
// for more options see `paypal-mobile-js-helper.js`
var config = new PayPalConfiguration({merchantName: shopSettings.payPalShopName});
return config;
}
function onPayPalMobileInit() {
$ionicPlatform.ready().then(function () {
// must be called
// use PayPalEnvironmentNoNetwork mode to get look and feel of the flow
PayPalMobile.prepareToRender(shopSettings.payPalEnv, configuration(), function () {
$timeout(function () {
init_defer.resolve();
});
});
});
}
function makePayment(total, name) {
var defer = $q.defer();
total = $filter('number')(total, 2);
$ionicPlatform.ready().then(function () {
PayPalMobile.renderSinglePaymentUI(createPayment(total, name), function (result) {
$timeout(function () {
defer.resolve(result);
});
}, function (error) {
$timeout(function () {
defer.reject(error);
});
});
});
return defer.promise;
}
})
and my settings
.constant('shopSettings',{
payPalSandboxId : 'id',
payPalProductionId : 'id',
payPalEnv: 'PayPalEnvironmentSandbox',
payPalShopName : 'app_name'
});
All I need is to make standard payment for user, so some user can log in in personal account, pay for some stuff and money will appear in my account.By the way everything works fine if I log in with sandbox test accounts, but not with real one's.
I have a meteor app that allows users to update their skype name, phone number, email address, etc. To help maintain a consistent code base I have implemented an EJSON type UserModel in a common directory so it can run on the client and server.
EJSON.addType("UserModel", function fromJSONValue(value) {
return new UserModel(value);
});
UserModel.prototype = {
constructor: UserModel,
//
// EJSON Ovverrides.
//
valueOf: function() {
return JSON.parse(JSON.stringify(this), function(key, value) {
var dateFields = ["expiration", "createdAt"];
if(_.contains(dateFields, key) && typeof value === "string") {
return new Date(value);
} else {
return value;
}
});
},
typeName: function() {
return 'UserModel';
},
toJSONValue: function() {
return this.valueOf();
},
clone: function() {
return new UserModel(this.valueOf());
},
equals: function(other) {
if(!(other instanceof UserModel)) {
return false;
}
return this._id === other._id;
},
setPhoneNumbers: function(phoneNumber, queueUpdate) {
var modifier = {$set: {
'profile.phoneNumber': phoneNumber
}};
this.profile.phoneNumber = phoneNumber;
return this._saveOrQueueUpdate(modifier, queueUpdate);
},
_saveOrQueueUpdate: function(modifier, queueUpdate) {
if (!queueUpdate) {
return Meteor.users.update(this._id, modifier, function(err, res) {
});
} else {
this.pendingUpdates.push(modifier);
return true;
}
}
I call the setPhoneNumbers method on the settings page js file like so.
'blur #phonenumber':function(){
var user = Meteor.user();
var number = $("#phonenumber").val();
if(number.length){
user.setPhoneNumbers(number);
}
}
The problem with this is that whenever I call the setPhoneNumbers method, the page takes >500ms to update and locks the entire page. I looked at the docs and according to this segment, client code should never be blocking. The page only locks up when updates happen so I know it has something to do with the UserModel. Any insight to what could be causing this would be very helpful. The page is extremely slow and it is unacceptable for a production app.
I think I'm writing my promise incorrectly and I couldn't figure out why it is caching data. What happens is that let's say I'm logged in as scott. When application starts, it will connect to an endpoint to grab listing of device names and device mapping. It works fine at this moment.
When I logout and I don't refresh the browser and I log in as a different user, the device names that scott retrieved on the same browser tab, it is seen by the newly logged in user. However, I can see from my Chrome's network tab that the endpoint got called and it received the correct listing of device names.
So I thought of adding destroyDeviceListing function in my factory hoping I'll be able to clear the values. This function gets called during logout. However, it didn't help. Below is my factory
app.factory('DeviceFactory', ['$q','User', 'DeviceAPI', function($q, User, DeviceAPI) {
var deferredLoad = $q.defer();
var isLoaded = deferredLoad.promise;
var _deviceCollection = { deviceIds : undefined };
isLoaded.then(function(data) {
_deviceCollection.deviceIds = data;
return _deviceCollection;
});
return {
destroyDeviceListing : function() {
_deviceCollection.deviceIds = undefined;
deferredLoad.resolve(_deviceCollection.deviceIds);
},
getDeviceIdListing : function() {
return isLoaded;
},
getDeviceIdMapping : function(deviceIdsEndpoint) {
var deferred = $q.defer();
var userData = User.getUserData();
// REST endpoint call using Restangular library
RestAPI.setBaseUrl(deviceIdsEndpoint);
RestAPI.setDefaultRequestParams( { userresourceid : userData.resourceId, tokenresourceid : userData.tokenResourceId, token: userData.bearerToken });
RestAPI.one('devices').customGET('', { 'token' : userData.bearerToken })
.then(function(res) {
_deviceCollection.deviceIds = _.chain(res)
.filter(function(data) {
return data.devPrefix != 'iphone'
})
.map(function(item) {
return {
devPrefix : item.devPrefix,
name : item.attributes[item.devPrefix + '.dyn.prop.name'].toUpperCase(),
}
})
.value();
deferredLoad.resolve(_deviceCollection.deviceIds);
var deviceIdMapping = _.chain(_deviceCollection.deviceIds)
.groupBy('deviceId')
.value();
deferred.resolve(deviceIdMapping);
});
return deferred.promise;
}
}
}])
and below is an extract from my controller, shortened and cleaned version
.controller('DeviceController', ['DeviceFactory'], function(DeviceFactory) {
var deviceIdMappingLoader = DeviceFactory.getDeviceIdMapping('http://10.5.1.7/v1');
deviceIdMappingLoader.then(function(res) {
$scope.deviceIdMapping = res;
var deviceIdListingLoader = DeviceFactory.getDeviceIdListing();
deviceIdListingLoader.then(function(data) {
$scope.deviceIDCollection = data;
})
})
})
Well, you've only got a single var deferredLoad per your whole application. As a promise does represent only one single asynchronous result, the deferred can also be resolved only once. You would need to create a new deferred for each request - although you shouldn't need to create a deferred at all, you can just use the promise that you already have.
If you don't want any caching, you should not have global deferredLoad, isLoaded and _deviceCollection variables in your module. Just do
app.factory('DeviceFactory', ['$q','User', 'DeviceAPI', function($q, User, DeviceAPI) {
function getDevices(deviceIdsEndpoint) {
var userData = User.getUserData();
// REST endpoint call using Restangular library
RestAPI.setBaseUrl(deviceIdsEndpoint);
RestAPI.setDefaultRequestParams( { userresourceid : userData.resourceId, tokenresourceid : userData.tokenResourceId, token: userData.bearerToken });
return RestAPI.one('devices').customGET('', { 'token' : userData.bearerToken })
.then(function(res) {
return _.chain(res)
.filter(function(data) {
return data.devPrefix != 'iphone'
})
.map(function(item) {
return {
devPrefix : item.devPrefix,
name : item.attributes[item.devPrefix + '.dyn.prop.name'].toUpperCase(),
};
})
.value();
});
}
return {
destroyDeviceListing : function() {
// no caching - nothing there to be destroyed
},
getDeviceIdListing : function(deviceIdsEndpoint) {
return getDevices(deviceIdsEndpoint)
.then(function(data) {
return { deviceIds: data };
});
},
getDeviceIdMapping : function(deviceIdsEndpoint) {
return this.getDeviceIdListing(deviceIdsEndpoint)
.then(function(deviceIds) {
return _.chain(deviceIds)
.groupBy('deviceId')
.value();
});
}
};
}])
Now, to add caching you'd just create a global promise variable and store the promise there once the request is created:
var deviceCollectionPromise = null;
…
return {
destroyDeviceListing : function() {
// if nothing is cached:
if (!deviceCollectionPromise) return;
// the collection that is stored (or still fetched!)
deviceCollectionPromise.then(function(collection) {
// …is invalidated. Notice that mutating the result of a promise
// is a bad idea in general, but might be necessary here:
collection.deviceIds = undefined;
});
// empty the cache:
deviceCollectionPromise = null;
},
getDeviceIdListing : function(deviceIdsEndpoint) {
if (!deviceCollectionPromise)
deviceCollectionPromise = getDevices(deviceIdsEndpoint)
.then(function(data) {
return { deviceIds: data };
});
return deviceCollectionPromise;
},
…
};