Local storage set Item replaces instead of update - javascript

I tried to save my data in local Storage with setItem but when I refresh the chrome tab and add data to my array, the data in localStorage delete the old data and set new data instead of updating that old data.
Here is my code:
let capacity = 200;
let reservedRooms = 0;
let users = [];
let rsBox = document.getElementById('reservebox');
class Reserver {
constructor(name , lastName , nCode , rooms){
this.name = name ;
this.lastName = lastName ;
this.nCode = nCode ;
this.rooms = rooms ;
}
saveUser(){
if(this.rooms > capacity){
console.log('more than capacity');
}else{
users.push({
name : this.name ,
lastName : this.lastName ,
id : this.nCode ,
rooms : this.rooms
});
capacity -= this.rooms ;
reservedRooms += this.rooms ;
}
}
saveData(){
localStorage.setItem('list',JSON.stringify(users));
}
}
rsBox.addEventListener('submit',function(e){
let rsName = document.getElementById('name').value;
let rsLastName = document.getElementById('lastname').value;
let rsNationalCode = Number(document.getElementById('nationalcode').value);
let rooms = Number(document.getElementById('rooms').value);
//Save the user data
let sign = new Reserver(rsName , rsLastName , rsNationalCode , rooms);
sign.saveUser();
sign.saveData();
e.preventDefault();
});

You are pushing an empty users array each time you reload the page, to resolve this you need to populate the users array from the items you have in storage.
e.g.
let users = [];
needs to be something like
let users = JSON.parse(localStorage.getItem('list')) || [];
The key point being that you need to load your existing users to be able to add to them, if you don't then you are essentially creating the users array fresh each time the page loads and you put data into it.
You may want to create something like a "loadData" function that checks if the array is initialized, loads it if it is and creates it if it isn't. You can make this generic so that you can use it to access any key and provide a default value if the key isn't present e.g.
function loadData(key, def) {
var data = localStorage.getItem(key);
return null == data ? def : JSON.parse(data)
}
then
// load "list" - set to an empty array if the key isn't present
let users = loadData('list', []);

Another option would be to change the saveData method so you won't have to load the localStorage when the app is loading:
saveData(){
let newList = JSON.parse(localStorage.getItem('list') || '[]')
if(users.length) newList.push(users[users.length - 1]);
localStorage.setItem('list',JSON.stringify(newList));
newList=null;
}
Note: Be careful with localStorage because it doesn't have the same capacity on all browsers, you can check this post for more information

Related

Get Key Value Given Other Key Value in FireBase

I am trying to find a way to find the value of the id given the email.
For example, If I had email2#gmail.com, It would give me the ID 108454568498950432898.
All emails are unique and there will be no repetition of emails.
This is my user tree:
Note: In the image it says email2 instead of email2#gmail.com. Ignore this
Here's my code so far:
(Code won't run obviously but it's easier to enter code using the embed)
var users;
var givenEmail = "email2#gmail.com";
var neededID;
var dataRef = firebase.database().ref('users');
dataRef.on('value', (snapshot) => {
const data = snapshot.val();
users = data;
});
var usersArray = Object.keys(users);
for(i = 0; i < usersArray.length; i++) {
if(users[i].email == givenEmail) {
neededID = i;
break;
}
}
I recommend using a query to perform the filtering on the server, instead of downloading the entire users node and filtering in your application code as you now do.
var givenEmail = "email2#gmail.com";
var dataRef = firebase.database().ref('users');
var query = dataRef.orderByChild('email').equalTo(givenEmail);
dataRef.once('value', (snapshot) => {
snapshot.forEach((userSnapshot) => {
console.log(userSnapshot.val().id);
});
});
Well, I think you are almost there.
users[i].email
you can retrieve the email using this method, and similarly you can do it with id too
users[i].id
Please note that you wanted to find email2#gmail.com but your firebase only have email2
Maybe you would want to change that

JavaScript - Issues recovering a map in an object after being saved in localStorage

I've been dealing with this for some time. I've a list of sections in which the user checks some checkboxes and that is sent to the server via AJAX. However, since the user can return to previous sections, I'm using some objects of mine to store some things the user has done (if he/she already finished working in that section, which checkboxes checked, etc). I'm doing this to not overload the database and only send new requests to store information if the user effectively changes a previous checkbox, not if he just starts clicking "Save" randomly. I'm using objects to see the sections of the page, and storing the previous state of the checkboxes in a Map. Here's my "supervisor":
function Supervisor(id) {
this.id = id;
this.verif = null;
this.selections = new Map();
var children = $("#ContentPlaceHolder1_checkboxes_div_" + id).children().length;
for (var i = 0; i < children; i++) {
if (i % 2 == 0) {
var checkbox = $("#ContentPlaceHolder1_checkboxes_div_" + id).children()[i];
var idCheck = checkbox.id.split("_")[2];
this.selections.set(idCheck, false);
}
}
console.log("Length " + this.selections.size);
this.change = false;
}
The console.log gives me the expected output, so I assume my Map is created and initialized correctly. Since the session of the user can expire before he finishes his work, or he can close his browser by accident, I'm storing this object using local storage, so I can change the page accordingly to what he has done should anything happen. Here are my functions:
function setObj(id, supervisor) {
localStorage.setItem(id, JSON.stringify(supervisor));
}
function getObj(key) {
var supervisor = JSON.parse(localStorage.getItem(key));
return supervisor;
}
So, I'm trying to add to the record whenever an user clicks in a checkbox. And this is where the problem happens. Here's the function:
function checkboxClicked(idCbx) {
var idSection = $("#ContentPlaceHolder1_hdnActualField").val();
var supervisor = getObj(idSection);
console.log(typeof (supervisor)); //Returns object, everythings fine
console.log(typeof (supervisor.change)); //Returns boolean
supervisor.change = true;
var idCheck = idCbx.split("_")[2]; //I just want a part of the name
console.log(typeof(supervisor.selections)); //Prints object
console.log("Length " + supervisor.selections.size); //Undefined!
supervisor.selections.set(idCheck, true); //Error! Note: The true is just for testing purposes
setObj(idSection, supervisor);
}
What am I doing wrong? Thanks!
Please look at this example, I removed the jquery id discovery for clarity. You'll need to adapt this to meet your needs but it should get you mostly there.
const mapToJSON = (map) => [...map];
const mapFromJSON = (json) => new Map(json);
function Supervisor(id) {
this.id = id;
this.verif = null;
this.selections = new Map();
this.change = false;
this.selections.set('blah', 'hello');
}
Supervisor.from = function (data) {
const id = data.id;
const supervisor = new Supervisor(id);
supervisor.verif = data.verif;
supervisor.selections = new Map(data.selections);
return supervisor;
};
Supervisor.prototype.toJSON = function() {
return {
id: this.id,
verif: this.verif,
selections: mapToJSON(this.selections)
}
}
const expected = new Supervisor(1);
console.log(expected);
const json = JSON.stringify(expected);
const actual = Supervisor.from(JSON.parse(json));
console.log(actual);
If you cant use the spread operation in 'mapToJSON' you could loop and push.
const mapToJSON = (map) => {
const result = [];
for (let entry of map.entries()) {
result.push(entry);
}
return result;
}
Really the only thing id change is have the constructor do less, just accept values, assign with minimal fiddling, and have a factory query the dom and populate the constructor with values. Maybe something like fromDOM() or something. This will make Supervisor more flexible and easier to test.
function Supervisor(options) {
this.id = options.id;
this.verif = null;
this.selections = options.selections || new Map();
this.change = false;
}
Supervisor.fromDOM = function(id) {
const selections = new Map();
const children = $("#ContentPlaceHolder1_checkboxes_div_" + id).children();
for (var i = 0; i < children.length; i++) {
if (i % 2 == 0) {
var checkbox = children[i];
var idCheck = checkbox.id.split("_")[2];
selections.set(idCheck, false);
}
}
return new Supervisor({ id: id, selections: selections });
};
console.log(Supervisor.fromDOM(2));
You can keep going and have another method that tries to parse a Supervisor from localStorageand default to the dom based factory if the localStorage one returns null.

localStorage .parse .stringify

I need help with pushing 2 data values into localStorage. I know a little about the stringify and parse methods but cant grasp how to implement them.The 2 data values are from "Scores" and "saveName"(a username that is put into an input box).
var Score = (answeredCorrect * 20) + (timeleft);
var saveName = document.querySelector("#saveName");
function Storage() {
localStorage.setItem("User", JSON.stringify(saveName.value));
localStorage.setItem("Scores", JSON.stringify(Score));
var GetStorage = localStorage.getItem("User");
var GetStorage2 = localStorage.getItem("Scores");
return {
first:console.log("GetStorage: "+ GetStorage + GetStorage2),
second:GetStorage,
third:GetStorage2,
};
};
var values = Storage();
var first = values.first;
var second = values.second;
var third = values.third;
As mentioned in the comments you need to parse it once retrieved from storage with JSON.parse, also naming Storage should be avoided.
Since your making a wrapper for localstorage, it could be done like this:
const Store = {
set: (key, value) => localStorage[key] = JSON.stringify(value),
get: key => JSON.parse(localStorage[key])
}
Then you can simply call it like the following, with a set and get methods:
//
Store.set('Score', Score)
Score = Store.get('Score')
//
Store.set('User', saveName.value)
saveName = Store.get('User')
Though you only need to get() on page load as you already have the value in Score/saveName etc.

SharePoint 2013 JSOM User Key From Person Field

Can anyone help me to get the user info from a person column using javascript? So far I have been able to read the list item and return a SP.FieldUserValue from which I can get a numeric Id (not sure what this ID is) and the display name. e.g.
var ManVal = oListItem.get_item("RecruitingManager").get_lookupValue();
var ManId = oListItem.get_item("RecruitingManager").get_lookupId();
How do I take this one step further to create a sp user object?
Ultimately what I'm trying to achieve is to retrieve the details from the list and then populate a people editor.
Ok, I've got it.
Here is my code, hope it helps somebody. I haven't included the method to retrieve the list item, just the line from that function where I'm getting the value of the person.
var _lineManager;
var lineManager = oListItem.get_item("RecruitingManager").get_lookupId();
_lineManager = oWebsite.getUserById(lineManager);
getLineManager();
function getLineManager() {
context.load(_lineManager);
context.executeQueryAsync(onGetUserNameSuccessLM, onGetUserNameFailLM);
}
function onGetUserNameSuccessLM() {
alert(lineManager.get_title());
var schema = {};
schema['PrincipalAccountType'] = 'User,DL,SecGroup,SPGroup';
schema['SearchPrincipalSource'] = 15;
schema['ResolvePrincipalSource'] = 15;
schema['AllowMultipleValues'] = false;
schema['MaximumEntitySuggestions'] = 50;
schema['Width'] = '280px';
var users = new Array(1);
var defaultUser = new Object();
defaultUser.AutoFillDisplayText = lineManager.get_title();
defaultUser.AutoFillKey = lineManager.get_loginName();
defaultUser.Description = lineManager.get_email();
defaultUser.DisplayText = lineManager.get_title();
defaultUser.EntityType = "User";
defaultUser.IsResolved = true;
defaultUser.Key = lineManager.get_loginName();
defaultUser.Resolved = true;
users[0] = defaultUser;
SPClientPeoplePicker_InitStandaloneControlWrapper('peoplePickerDivLinMan', users, schema);
}
function onGetUserNameFailLM(sender, args) {
alert('Failed to get user name. Error:' + args.get_message());
}
The person field (actually called "people picker") has a specific JavaScript function which you might find useful: GetAllUserInfo()
There is a nice article on MSDN:
How to: Use the client-side People Picker control in apps for SharePoint
The relevant code is:
// Get the people picker object from the page.
var peoplePicker = this.SPClientPeoplePicker.SPClientPeoplePickerDict.peoplePickerDiv_TopSpan;
// Get information about all users.
var users = peoplePicker.GetAllUserInfo();
var userInfo = '';
for (var i = 0; i < users.length; i++) {
var user = users[i];
for (var userProperty in user) {
userInfo += userProperty + ': ' + user[userProperty] + '<br>';
}
}
$('#resolvedUsers').html(userInfo);
// Get user keys.
var keys = peoplePicker.GetAllUserKeys();
$('#userKeys').html(keys);
So basically you have to cast your field to a SPClientPeoplePicker and can then use GetAllUserInfo to iterate over all users in the field.

return from JS function

basic JS question, please go easy on me I'm a newb :)
I pass 2 variables to the findRelatedRecords function which queries other related tables and assembles an Array of Objects, called data. Since findRelatedRecords has so many inner functions, I'm having a hard time getting the data Array out of the function.
As it currently is, I call showWin inside findRelatedRecords, but I'd like to change it so that I can get data Array directly out of findRelatedRecords, and not jump to showWin
function findRelatedRecords(features,evtObj){
//first relationship query to find related branches
var selFeat = features
var featObjId = selFeat[0].attributes.OBJECTID_1
var relatedBranch = new esri.tasks.RelationshipQuery();
relatedBranch.outFields = ["*"];
relatedBranch.relationshipId = 1; //fac -to- Branch
relatedBranch.objectIds = [featObjId];
facSel.queryRelatedFeatures(relatedBranch, function(relatedBranches) {
var branchFound = false;
if(relatedBranches.hasOwnProperty(featObjId) == true){
branchFound = true;
var branchSet = relatedBranches[featObjId]
var cmdBranch = dojo.map(branchSet.features, function(feature){
return feature.attributes;
})
}
//regardless of whether a branch is found or not, we have to run the cmdMain relationship query
//the parent is still fac, no advantage of the parent being branch since cmcMain query has to be run regardless
//fac - branch - cmdMain - cmdSub <--sometimes
//fac - cmdMain - cmdSub <-- sometimes
//second relationship query to find related cmdMains
var relatedQuery = new esri.tasks.RelationshipQuery();
relatedQuery.outFields = ["*"];
relatedQuery.relationshipId = 0; //fac -to- cmdMain
relatedQuery.objectIds = [featObjId];
//rather then listen for "OnSelectionComplete" we are using the queryRelatedFeatures callback function
facSel.queryRelatedFeatures(relatedQuery, function(relatedRecords) {
var data = []
//if any cmdMain records were found, relatedRecords object will have a property = to the OBJECTID of the clicked feature
//i.e. if cmdMain records are found, true will be returned; and continue with finding cmdSub records
if(relatedRecords.hasOwnProperty(featObjId) == true){
var fset = relatedRecords[featObjId]
var cmdMain = dojo.map(fset.features, function(feature) {
return feature.attributes;
})
//we need to fill an array with the objectids of the returned cmdMain records
//the length of this list == total number of mainCmd records returned for the clicked facility
objs = []
for (var k in cmdMain){
var o = cmdMain[k];
objs.push(o.OBJECTID)
}
//third relationship query to find records related to cmdMain (cmdSub)
var subQuery = new esri.tasks.RelationshipQuery();
subQuery.outFields = ["*"];
subQuery.relationshipId = 2;
subQuery.objectIds = [objs]
subTbl.queryRelatedFeatures(subQuery, function (subRecords){
//subRecords is an object where each property is the objectid of a cmdMain record
//if a cmdRecord objectid is present in subRecords property, cmdMain has sub records
//we no longer need these objectids, so we'll remove them and put the array into cmdsub
var cmdSub = []
for (id in subRecords){
dojo.forEach(subRecords[id].features, function(rec){
cmdSub.push(rec.attributes)
})
}
var j = cmdSub.length;
var p;
var sub_key;
var obj;
if (branchFound == true){
var p1 = "branch";
obj1 = {};
obj1[p1] = [cmdBranch[0].Branches]
data.push(obj1)
}
for (var i=0, iLen = cmdMain.length; i<iLen; i++) {
p = cmdMain[i].ASGMT_Name
obj = {};
obj[p] = [];
sub_key = cmdMain[i].sub_key;
for (var j=0, jLen=cmdSub.length; j<jLen; j++) {
if (cmdSub[j].sub_key == sub_key) {
obj[p].push(cmdSub[j].Long_Name);
}
}
data.push(obj);
}
showWin(data,evtObj) <---this would go away
})
}
//no returned cmdRecords; cmdData not available
else{
p = "No Data Available"
obj = {}
obj[p] = []
data.push(obj)
}
showWin(data,evtObj) <--this would go away
})
})
}
I'd like to have access to data array simply by calling
function findRelatedRecords(feature,evt){
//code pasted above
}
function newfunct(){
var newData = findRelatedRecords(feature,evt)
console.log(newData)
}
is this possible?
thanks!
Edit
Little more explanation.....
I'm connecting an Object event Listener to a Function like so:
function b (input){
dojo.connect(obj, "onQueryRelatedFeaturesComplete", getData);
obj.queryRelatedFeatures(input);
console.log(arr) //<----this doesn't work
}
function getData(relatedFeatData){
var arr = [];
//populate arr
return arr;
}
So when obj.QueryRelatedFeatures() is complete, getData fires; this part works fine, but how to I access arr from function b ?
Post Edit Update:
Due to the way that this event is being hooked up you can't simple return data from it. Returning will just let Dojo call to the next method that is hooked up to onSelectionComplete.
When init runs it is long before findRelatedRecords will ever be executed/fired by the onSelectionComplete event of the well, which is why you were seeing undefined/null values. The only way to work with this sort of system is to either 1) call off to a method like you're already doing or 2) fire off a custom event/message (technically it's still just calling off to a method).
If you want to make this method easier to work with you should refactor/extract snippets of it to make it a smaller function but contained in many functions. Also, changing it to have only one exit point at the end of the findRelatedRecords method will help. The function defined inside of subTbl.queryRelatedFeatures() would be a great place to start.
Sorry, you're kind of limited by what Dojo gives you in this case.
Pre Edit Answer:
Just return your data out of it. Everywhere where there is a showWin call just use this return.
return {
data: data,
evtObj: evtObj
}
Then your newfunct would look like this.
function newfunct(){
var newData = findRelatedRecords(feature,evt);
console.log(newData);
console.log(newData.data);
console.log(newData.evtObj);
}
If you only need that "data" object, then change your return to just return data;.
Also, start using semicolons to terminate statements.

Categories

Resources