localStorage returning undefined until refresh? - javascript

I've noticed a bug, or what I believe to be a bug, in the localStorage which is hard to explain but I'll try.
I'm writing a simple local shopping cart. In order for things to work properly I check if the storage already exists and put an empty array into it if that isn't the case.
However, even after this check localStorage still remains undefined untill the second time I refresh the page. See the code below:
const cart = function(name) {
this.storageNamespace = name;
this.get = store.get(this.storageNamespace);
};
cart.prototype.set = function (data) {
store.set(this.storageNamespace, data);
}
cart.prototype.add = function (item) {
if (this.get === undefined) {
store.set(this.storageNamespace, []);
}
let cart = this.get;
if (cart.length !== 0) {
for (let i = 0; i < cart.length; i++) {
if (cart[i].id === item.id) {
cart[i].ammount = Number(cart[i].ammount) + Number(item.ammount);
this.set(cart);
break;
} else if (i === cart.length - 1) {
cart.push(item);
this.set(cart);
break;
}
}
} else {
cart.push(item);
this.set(cart);
}
}
A few things. Yes, this.get returns undefined, I have tested it from the console. Hence I don't understnad why the code inside of the if statement isn't running. I've put the if statement in several places, including the constructor. Same behaviour everywhere.
It all works fine on the second visit though.
To be clear the code that is doing nothing even though it seems to evaluate to true is:
if (this.get === undefined) {
store.set(this.storageNamespace, []);
}

const cart = function(name) {
this.storageNamespace = name;
this.get = store.get(this.storageNamespace); /* store.get is function
call, value be will initialized once instance of this function is created */
};
When you create instance of this function for the first time, an object with "get" property - undefined is created, because you don't have any value in localstorage initially.
cart.prototype.add = function (item) {
if (this.get === undefined) {
store.set(this.storageNamespace, []); /* Here, you insert value in
localstorage,but object's 'get' property is still undefined,i.e there is
value in localstorage but not in this object's property */
// *** Missed this -> this.get = store.get(this.storageNameSpace)
}
let cart = this.get; /* undefined, hence 'if' is not executed */
if (cart.length !== 0) {
for (let i = 0; i < cart.length; i++) {
if (cart[i].id === item.id) {
cart[i].ammount = Number(cart[i].ammount) + Number(item.ammount);
this.set(cart);
break;
} else if (i === cart.length - 1) {
cart.push(item);
this.set(cart);
break;
}
}
} else {
cart.push(item);
this.set(cart);
}
}

Related

angular.isUndefined() function working abruptly

angular.module("customFilters", [])
.filter("unique", function () {
return function (data, propertyName) {
if (angular.isArray(data) && angular.isString(propertyName)) {
var results = [];
var keys = {};
for (var i = 0; i < data.length; i++) {
var val = data[i][propertyName];
console.log(angular.isUndefined(keys[val]))
if (angular.isUndefined(keys[val])) {
keys[val] = true;
results.push(val);
}
}
return results;
} else {
return data;
}
}
});
i am new to angularjs and facing problem with angular.isUndefined() function.
So the issue is like i am adding properties to an object with the help of for loop and also checking that if a particular property is already defined for the object, if the property is defined then i am not adding that property to the object but when i am using angular.isUndefined() to check the property it returns false even when the property is there in the object and keeps doing so two times and for the third time it returns true when i call angular.isUndefined().
Please help in here.

Trying to check if object exists in Knockout Observable Array

I'm trying to check if an object has the same observable values of other objects with the same observable properties inside an observable array.
I created a foreach loop which evaluates if any of the observables match. The problem I'm having is that condition always evaluates to true, even though these values are different. I'm using typescript and knockout.
Here's the code :
export function addPDFToPackage(heat: MTRHeat): void {
var koHeat: MTRHeatWithInclude = ko.mapping.fromJS(heat);
koHeat.Include = ko.observable(true);
var arrayOfHeats = model.mtrPackage.Heats();
var addToHeats = () => model.mtrPackage.Heats.push(koHeat);
var duplicate = false;
arrayOfHeats.forEach(function (koHeat, i) {
if (arrayOfHeats[i].MTRID() == koHeat.MTRID() && arrayOfHeats[i].HeatID() == koHeat.HeatID() && arrayOfHeats[i].PartID() == koHeat.PartID()) {
duplicate = true;
}
else
duplicate = false;
})
if (!!model.mtrPackage.PackageID()) {
if (duplicate) {
var c = confirm("Warning: Duplicate MTR located on current package.Proceed ?")
if (c) {
ServiceMethods.addHeatToPackage(model.mtrPackage.PackageID(), heat.HeatID).done(addToHeats);
}
if (!c) {
return;
}
}
}
}
First problem: Your loop compares each object to itself because you re-use the variable name koHeat. I believe you really wanted to refer to the "outer" koHeat.
Second problem: You overwrite the duplicate variable in every loop iteration. This is probably not what you intend. Instead you want to stop the loop as soon as a duplicate is found.
How about something along those lines?
export function addPDFToPackage(heat: MTRHeat): void {
var koHeat: MTRHeatWithInclude = ko.mapping.fromJS(heat);
var packageId = model.mtrPackage.PackageID();
koHeat.Include = ko.observable(true);
function equals(a: MTRHeatWithInclude, b: MTRHeatWithInclude): boolean {
return a.MTRID() == b.MTRID() && a.HeatID() == b.HeatID() && a.PartID() == b.PartID();
}
if ( !!packageId && (
!model.mtrPackage.Heats().some(item => equals(item, koHeat)) ||
confirm("Warning: Duplicate MTR located on current package.Proceed ?")
)
) {
ServiceMethods.addHeatToPackage(packageId, heat.HeatID).done(() => {
model.mtrPackage.Heats.push(koHeat);
});
}
}
The equals() function should ideally be a method of the MTRHeatWithInclude class.
I think you're getting a clash between koHeat defined here:
var koHeat: MTRHeatWithInclude = ko.mapping.fromJS(heat);
koHeat.Include = ko.observable(true);
And the variable defined within the forEach call. It's always returning true as (within the scope of the forEach) arrayOfHeats[i] === koHeat.
Try this:
export function addPDFToPackage(heat: MTRHeat): void {
var koHeat: MTRHeatWithInclude = ko.mapping.fromJS(heat);
koHeat.Include = ko.observable(true);
var arrayOfHeats = model.mtrPackage.Heats();
var addToHeats = () => model.mtrPackage.Heats.push(koHeat);
var duplicate = false;
arrayOfHeats.forEach(function (koHeat2, i) {
if (koHeat2.MTRID() == koHeat.MTRID() &&
koHeat2.HeatID() == koHeat.HeatID() &&
koHeat2.PartID() == koHeat.PartID()) {
duplicate = true;
}
})
if (!!model.mtrPackage.PackageID()) {
if (duplicate) {
var c = confirm("Warning: Duplicate MTR located on current package.Proceed ?")
if (c) {
ServiceMethods.addHeatToPackage(model.mtrPackage.PackageID(), heat.HeatID).done(addToHeats);
} else {
return;
}
}
}
}

creating a service in angularJS, using restangular promises

Ok, this is driving me mad, basically what I am trying to do is create a service to get and evaluate user capabilities, I am using WP REST API. I use restangular to get my JSON data.
At this stage I am testing the function in the controller itself, but no matter where I test it, be it in my custom service using this.method or inside the controller, with or without using $scope the result is always undefined. I know I am missing something either in the way I am returning true or false inside the function, or there is something fundamentally different when it comes to promises in JS. Here is the code:
var current_user = parseInt(o2_i18n.user_id),
currentUserCapabilities,
capability;
$scope.currentUserCan = function(capability) {
if(current_user !== '0') {
wpAPIResource.one('users').get()
.then(function(allUsers){
for (var i = 0; i < allUsers.length; i++) {
if ( allUsers[i].id === current_user ) {
var currentUserCapabilities = allUsers[i].capabilities;
for(var prop in currentUserCapabilities){
if (capability === prop) {
//$log.log( prop );
return prop;
} else {
//$log.log( prop );
return false;
}
}
}
}
}, function(reason){
$log.error(reason);
});
} else {
//The user is not logged in, therefor no capabilities
return false;
}
};
$log.log($scope.currentUserCan('publish_posts'));
if ( $scope.currentUserCan('publish_posts') ) {
$log.log( 'Yes I Can!' );
} else {
$log.warn('No Can\'t Do!');
}
Your currentUserCan function doesn't return anything if current_user !== '0'. You should have it return a promise, for example (for the following you'll need to inject the $q service)
$scope.currentUserCan = function(capability) {
if(current_user !== '0') {
// note the "return" here
return wpAPIResource.one('users').get().then(function(allUsers){
for (var i = 0; i < allUsers.length; i++) {
if ( allUsers[i].id === current_user ) {
var currentUserCapabilities = allUsers[i].capabilities;
for(var prop in currentUserCapabilities){
if (capability === prop) {
return prop;
}
}
}
}
return false;
}, function(reason){
$log.error(reason);
return $q.reject(reason); // you still want the promise to fail
});
} else {
return $q.resolve(false);
// this turns the static value into a promise so the API for this
// function is consistent
}
};
then consume the function like this
$scope.currentUserCan('publish_posts').then(function(can) {
if (can) {
$log.log('Yes I Can!');
} else {
$log.warn("No Can't Do!");
}
});
I also cleaned up your loop a little. In your OP, there was no point in the inner loop and you didn't have a return value if the user was not found in the allUsers array.

save variables in local storage and then compare

Due to the site I am working on I need to first store some variables and then compare them.
I can't get my fiddle to work if my values are indeed equal. I have never used local storage before so not sure if I am doing it correctly.
Fiddle is http://jsfiddle.net/ktcle/QuLub/2/
I have just added in the values in the divs so that it is easy to see what they are and won't be in the code.
var userID = user(2, 7),
playerID = player(14),
savedUserid,
savedUPlayerid;
function user(a, b) {
return a * b
}
function player(a) {
return a
}
function saveData(x) {
localStorage.setItem('userID', x);
}
function saveData(x) {
localStorage.setItem('playerID', x);
}
savedUserid = parseInt(localStorage.getItem('userID'));
savedPlayerid = parseInt(localStorage.getItem('playerID'));
if (typeof savedUserid === typeof savedPlayerid) {
alert (true)
}
else {
alert (false)
}
There were a few problems... you werent saving the values, and you were comparing typeof instead of the actual values (as someone else pointed out). Anyway, this is working:
http://jsfiddle.net/QuLub/7/
var userID = user(2, 7),
playerID = player(14),
savedUserid,
savedUPlayerid;
function user(a, b) {
return a * b
}
function player(a) {
return a
}
function saveData(type, value) {
localStorage.setItem(type, value);
}
saveData('userID', userID);
saveData('playerID', playerID);
console.log(localStorage.getItem('userID'));
savedUserid = parseInt(localStorage.getItem('userID'));
savedUPlayerid = parseInt(localStorage.getItem('playerID'));
if (savedUserid === savedUPlayerid) {
alert (true)
}
else {
alert (false)
}
document.getElementById("user").innerHTML = savedUserid;
document.getElementById("player").innerHTML = savedUPlayerid;
The first and main problem I notice is that you never call the saveData function. Also, as you can see, you have 2 functions with the same name, so they will just replace one another.
function saveData(x) {
localStorage.setItem('userID', x);
}
function saveData(x) {
localStorage.setItem('playerID', x);
}
Because of this,
localStorage.getItem('userID')
and
localStorage.getItem('playerID')
are both null.
The second mistake is that you misspelled: savedPlayerid as savedPlayrerid.
Working jsFiddle with the modifications: http://jsfiddle.net/QuLub/3/

How to accomplish this without using eval

Sorry for the title but I don't know how to explain it.
The function takes an URI, eg: /foo/bar/1293. The object will, in case it exists, be stored in an object looking like {foo: { bar: { 1293: 'content...' }}}. The function iterates through the directories in the URI and checks that the path isn't undefined and meanwhile builds up a string with the code that later on gets called using eval(). The string containing the code will look something like delete memory["foo"]["bar"]["1293"]
Is there any other way I can accomplish this? Maybe store the saved content in something other than
an ordinary object?
remove : function(uri) {
if(uri == '/') {
this.flush();
return true;
}
else {
var parts = trimSlashes(uri).split('/'),
memRef = memory,
found = true,
evalCode = 'delete memory';
parts.forEach(function(dir, i) {
if( memRef[dir] !== undefined ) {
memRef = memRef[dir];
evalCode += '["'+dir+'"]';
}
else {
found = false;
return false;
}
if(i == (parts.length - 1)) {
try {
eval( evalCode );
} catch(e) {
console.log(e);
found = false;
}
}
});
return found;
}
}
No need for eval here. Just drill down like you are and delete the property at the end:
parts.forEach(function(dir, i) {
if( memRef[dir] !== undefined ) {
if(i == (parts.length - 1)) {
// delete it on the last iteration
delete memRef[dir];
} else {
// drill down
memRef = memRef[dir];
}
} else {
found = false;
return false;
}
});
You just need a helper function which takes a Array and a object and does:
function delete_helper(obj, path) {
for(var i = 0, l=path.length-1; i<l; i++) {
obj = obj[path[i]];
}
delete obj[path.length-1];
}
and instead of building up a code string, append the names to a Array and then call this instead of the eval. This code assumes that the checks to whether the path exists have already been done as they would be in that usage.

Categories

Resources