How to avoid having my localStorage variable over written - javascript

var s = 0;
btn.addEventListener('click', function() {
var ModelMake = prompt("Enter The Model Make"),
ModelYear = prompt("Enter The Model Year"),
Km = prompt("Enter The Amount Of Km"),
Price = prompt("Enter The Price"),
Status = prompt("Enter The Car's Status"),
FinalPrice,
Details = prompt("Enter the Details");
localStorage.setItem(s += 1, JSON.stringify({
ModelMake: ModelMake,
ModelYear: ModelYear,
Km: Km,
Price: Price,
Status: Status,
Details: Details,
FinalPrice: FinalPrice
}));
How do i avoid having my previous localStorage objects overwritten after the user REFRESHES or CLOSES the browser. The reason i capitalized is to emphasize that this code works and keeps generating different objects by incrementing as long as the user doesn't refresh or close the browser. the moment you refresh or reopen the application then enter new values the previous objects get overwritten with the new ones and the incrementation starts all over from 1 (overwriting the previous 1).

Try this.
I've created a new variable index which store the value of s at the end of each run.
This value is read while initializing s the next time user opens the page, so that you can continue where you left off.
var s = 0; // Problem lies here
if(typeof(Storage)!=="undefined")
{
s = parseInt(localStorage.getItem("index"));
}
btn.addEventListener('click', function() {
var ModelMake = prompt("Enter The Model Make"),
ModelYear = prompt("Enter The Model Year"),
Km = prompt("Enter The Amount Of Km"),
Price = prompt("Enter The Price"),
Status = prompt("Enter The Car's Status"),
FinalPrice,
Details = prompt("Enter the Details");
localStorage.setItem(s += 1, JSON.stringify({
ModelMake: ModelMake,
ModelYear: ModelYear,
Km: Km,
Price: Price,
Status: Status,
Details: Details,
FinalPrice: FinalPrice
}));
localStorage.setItem('index', s);
});

You can get the values first on app load and create.
Actually rather than setting it to 0 initially, store that as 'index' in your localstorage. Then you can pick up where you left off

Related

Value from Session Storage as a number?

I have two values on my html: "Money" and "Time", and those values come from Session Storage, depending on what the person filled previously in another html page. So lets say the person filled that they need to pay $100 in 2 days.
So the idea would be for the result to be displayed on my HTML like:
$50
$50
If the number of days increased to 4, for example, the result would be:
$25
$25
$25
$25
When i hard code random numbers as the values for "Money" and "Time", the result is exactly what i need, just like the example above. But whenever i try to get the values from Session Storage, the result is always ONE topic of the <li> that i wanted to create, just like the example below:
Money: 100 / Days: 2
$50
My code so far:
<p id="money-value"></p>
<p id="time-value"></p>
<div id="payments"></div>
<script>
const displayMoney = document.getElementById("money-value");
const storedMoney = parseInt(sessionStorage.getItem("Money"));
window.addEventListener("load", () => {
displayMoney.innerHTML = "Money: " + storedMoney
});
const displayTime = document.getElementById("time-value");
const storedTime = parseInt(sessionStorage.getItem("Time"));
window.addEventListener("load", () => {
displayTime.innerHTML = "Time: " + storedTime
});
var calc = storedMoney / storedTime;
for (let i = 0; i < storedTime; i++) {
var list = document.createElement("li");
list.innerText = `${calc}`;
document.getElementById("payments").appendChild(list);
}
</script>
TL;DR
What i'm really struggling with, is to make the <li> display the payments in the same number of topics as the number of days.

How to calculate and make the result be displayed on HTML?

I have two values on my html: "Money" and "Time", and those values come from Session Storage, depending on what the person filled previously on another html page. So lets say the person filled that they need to pay $100 in 2 days.
What i'm trying to do, is to create a list, showing the number of payments, with the amount to be paid in each payment. Like the example below
MONEY: $100 / TIME: 2 Days
RESULT:
$50
$50
So if the person has 5 days, instead of 2, it would appear as:
$20
$20
$20
$20
$20
For some reason, when i try my code at codepen, using random numbers instead of the values i have on Session Storage, it works just fine, but when using the numbers from Session Storage, the result is always the same: I have a <li> with just one "topic" like:
MONEY: $100 / TIME: 2 Days
RESULT:
$50
I read somewhere that it might be because my values where stored as strings, but i don't know if thats correct, nor do i know how to undo that.
Current code below:
<p id="money-value"></p>
<p id="time-value"></p>
<div id="payments"></div>
<script>
const displayMoney = document.getElementById("money-value");
const storedMoney = sessionStorage.getItem("Money")
window.addEventListener("load", () => {
displayMoney.innerHTML = "Money: " + storedMoney
});
const displayTime = document.getElementById("time-value");
const storedTime = sessionStorage.getItem("Time")
window.addEventListener("load", () => {
displayTime.innerHTML = "Time: " + storedTime
});
var calc = storedMoney / storedTime;
for (let i = 0; i < storedTime; i++) {
var list = document.createElement("li");
list.innerText = `${calc}`;
document.getElementById("payments").appendChild(list);
}
sessionStorage.getItem("Time")
will only return the first item that matches the selector. This is similar to document.querySelector("selector"), which will only return the first instance of a match with that selector, whereas document.querySelectorAll("selector") will give you all the elements with that selector.
getItem does not have such an All alternative.
Instead, use keys. Check out some solutions for your problem in this post (probably the easiest is the forEach): Javascript: Retrieve all keys from sessionStorage?

Populating table with textbox value from previous HTML page

I have some JS that stores the name and value of selected checkboxes on one page and then, on a button click, adds this data to a table on page 2.
This works, but now I am looking to do the same for a textbox containing a number. Specifically, I'm looking to take the value entered by the user and add this to a cell in the table. What would be the best way to approach this? Add to the existing function or create a separate on button click function specifically for the textbox value?
I have added a screenshot of the HTML table on page 2 along with where I would like the textbox value to go (highlighted with a red rectangle).
Here's what I have so far:
HTML for textbox (page 1):
<div class="selecttier">
<h1>5. Number of Clicks</h1>
<input id="numberofclickstextbox" name="numberofclicks" type="text" value="0" data-total="0" oninput="calculatetier()" />
</div>
JS on page 1:
$('#sales_order_form_button').click(function() {
let table_info = [];
$('input[type=checkbox]').each(
function(index, value) {
if($(this).is(':checked')) {
table_info.push(
{
name: $(this).attr('name'),
value: $(this).attr('value'),
}
);
}
});
let base64str=btoa(JSON.stringify(table_info));
window.location = "page2.html?table_data=" + base64str;
});
JS on page 2:
// Helper function
function getUrlParameter(name) {
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
var regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
var results = regex.exec(location.href);
return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
};
// actual code
let table_data = getUrlParameter('table_data');
let data_from_page_1 = JSON.parse(atob(table_data));
for(let i = 0; i < data_from_page_1.length; i++){
let row = $("<tr></tr>");
let recordName = $("<td></td>").text(data_from_page_1[i].name);
let recordValue = $("<td></td>").text(data_from_page_1[i].value);
row.append(recordName, recordValue);
$('#output_table').append(row);
}
// code to sum CPC column
var sum1 = 0;
$("#output_table tr > td:nth-child(2)").each(
(_,el) => sum1 += Number($(el).text()) || 0
);
$("#sum1").text(sum1);
//datetime stamp
var dt = new Date();
document.getElementById("datetime").innerHTML = dt.toLocaleString();
Output HTML table (page 2):
<table id="output_table">
<tr>
<th>Name</th>
<th>Value</th>
<th>Number of Clicks</th>
</tr>
<tfoot>
<tr>
<th id="total" colspan="1">Total CPC:</th>
<td id="sum1"></td>
</tr>
</tfoot>
</table>
As stated in the #Manu Varghese comment, the way to go would be using sessionStorage or localStorage.
First, let's differentiate both. According to the Stack Overflow question "HTML5 Local storage vs Session Storage", we have the following answer:
localStorage and sessionStorage both extend Storage. There is no difference between them except for the intended "non-persistence" of sessionStorage.
That is, the data stored in localStorage persists until explicitly deleted. Changes made are saved and available for all current and future visits to the site.
For sessionStorage, changes are only available per tab. Changes made are saved and available for the current page in that tab until it is closed. Once it is closed, the stored data is deleted.
Considering they are used the same way and you must to choose between what better fits your case, I will proceed using sessionStorage.
For that, in the first page you must use:
sessionStorage.setItem("key", "value")
You may set the item right when you perceives a change, like in the input 'blur' event.
and when you land in the second page (right when jQuery calls its start event), you will retrieve your data using:
sessionStorage.getItem("key")
Take in mind that localStorage/sessionStorage can support a limited amount of data. Even if that limit is way bigger than URL, most browsers will store only 2.5MB to 10MB per origin, according to the browser implementation (you may test by yourself in the link recommended in MDN (Mozilla Development Network), http://dev-test.nemikor.com/web-storage/support-test/).
Also, you may want to avoid storing sensitive data in the storages, due to some some discussions about security, which seems not to be a complaint here.
Implementation in the given case
Your code can be modified in three steps:
Change the way you save the data to use the storage
Creates a JSON of an object containing the array, instead the make the JSON using the array itself. Then you can add more fields.
Load the JSON object and its fields (the array and the number).
Step 1 - Changing to sessionStorage
Just now you have your Javascript on page 1 creating an array of data and stringifying that data to a JSON string.
If you want to use the storage rather than the URL for all the data, just change these lines of code from:
let base64str=btoa(JSON.stringify(table_info));
window.location = "page2.html?table_data=" + base64str;
to the code that will save the data into a (local/session)Storage:
let jsonStr=JSON.stringify(table_info); // converts to JSON string
sessionStorage.setItem("oldData", jsonStr); // save to storage
window.location = "page2.html"; // navigate to other page
Notice that the storage can receive any string, but only strings, then we can remove the btoa function, but we must keep the stringify.
Step 2 -- Adding more data to save
Now you have one JSON that is an array of items. But what do you want is to include one more field, parallel to this array. Of course, you can't include it in the array, as it is a different thing. So, what we must to do is to create a JSON object which has a number field AND the array field itself.
Your function to create the array is all ok, then we will use the same "table_data" as the array and include it to a new JSON object:
let table_data = []; // the array you have
$('input[type=checkbox]').each(
... rest of code ...
); // the function that creates the array (I abbreviated it here)
// Creates an object with an array and a number
let jsonObj = {
table_data: table_data,
number_of_clicks: theNumberYouHave/* your variable with the number here */
};
// This is the bit above with CHANGES into variable names
// Instead of "table_data", now we save "jsonObj"
let jsonStr=JSON.stringify(jsonObj); // converts the "jsonObj" to a JSON string
sessionStorage.setItem("oldData", jsonStr);
window.location = "page2.html";
Remember to change "theNumberYouHave" to whatever your variable with the number is called. The you will append the number as a field of the JSON object.
In other words, this simply will create an structure like that:
{
number_of_clicks: 5216,
table_data: [
{ name: "...", value: "..."},
{ name: "...", value: "..."},
{ name: "...", value: "..."},
...
]
}
See? Your table_data is still there, but with a new sibling (number_of_clicks) inside an object.
Step 3 -- Loading data from page 1
For now, you have these two lines of code in page 2 to read data from page 1:
let table_data = getUrlParameter('table_data');
let data_from_page_1 = JSON.parse(atob(table_data));
What do you need there, is to simply replace the getUrlParameter function to read from the storage, and remove the atob function to reflect the changes we made in page 1, this way:
let jsonObj = sessionStorage.getItem("oldData"); // reads the string
let data_from_page_1 = JSON.parse(jsonObj); // parse the JSON string
let table_data = data_from_page_1.table_data; // grab the table data
let number_of_clicks = data_from_page_1.number_of_clicks; // grab the number
Now you are free to use the variable "table_data" like you did, and to use the "number_of_clicks" in the way you want to use it. It is the number passed from page 1, then you may set it to your table cell.
You have it with the unique ID "sum1", the you may just:
$("#sum1").text(number_of_clicks);
And you are done!
I highly recommend localStorage and sessionStorage to be used, as per this and this
Page 1 code full source
$('#next_page_button').click(function(){
let table_info = [];
// Do for checkboxes
$('.campaignstrategy input[type=checkbox]').each(
function(index, value){
if($(this).is(':checked')){
table_info.push(
{
name: $(this).attr('name'),
value: $(this).attr('value'),
type: 'checkbox'
}
);
}
});
$('.campaignstrategy input[type=text]').each(
function(index, value){
table_info.push(
{
name: $(this).attr('name'),
value: $(this).attr('value'),
type: 'text'
}
);
});
let base64str=btoa(JSON.stringify(table_info));
window.location = "page2.html?table_data=" + base64str;
});
Page 2 Code full source
// Helper function
function getUrlParameter(name) {
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
var regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
var results = regex.exec(location.href);
return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
};
// actual code
let table_data = getUrlParameter('table_data');
let data_from_page_1 = JSON.parse(atob(table_data));
// clear table
$('#output_table').html("");
// generator checboxes
for(let i=0;i<data_from_page_1.length;i++){
if(data_from_page_1[i].type == "checkbox"){
let row = $("<tr></tr>");
let recordName = $("<td></td>").text(data_from_page_1[i].name);
let recordValue = $("<td></td>").text(data_from_page_1[i].value);
let recordCount = $("<td></td>").text("");
row.append(recordName, recordValue, recordCount); // not used but needed
$('#output_table').append(row);
}
}
// generate textboxes
for(let i=0;i<data_from_page_1.length;i++){
if(data_from_page_1[i].type == "text"){
let row = $("<tr></tr>");
let recordName = $("<td></td>").text("");
let recordValue = $("<td></td>").text("");
let recordCount = $("<td></td>").text(data_from_page_1[i].value);
row.append(recordName, recordValue, recordCount);
$('#output_table').append(row);
}
}
ANSWER:
What would be the best way to approach this?
window.localStorage - stores data with no expiration date
window.sessionStorage - stores data for one session

CRM: Javascript to Set Multiple Email Addresses when Replying to an Email

On CRM 2013 I'm trying to insert multiple participants into the email "to" field when users click on "Reply All". However I need to remove certain email addresses from the To line. So I created an array to loop and get all the email addresses except the one that needs to be removed.
However the problem here is that it only works if there is only one participant left after removing the unwanted participants. If there are two or more participants the script will not populate any participants at all.
Is there a way to populate multiple email participants? Or is there a better approach than what I'm trying to do here?
Here's my code:
var toParty = Xrm.Page.getAttribute("to").getValue();
var partyListArray = new Array();
for (var indxAttendees = 0; indxAttendees < toParty.length; indxAttendees++) {
// using oData to get participant email address
var email = getParticipantEmail(
toParty[indxAttendees].entityType,
toParty[indxAttendees].id
);
if (email != "test#test.com") {
partyListArray[indxAttendees] = new Object();
partyListArray[indxAttendees].id = toParty[indxAttendees].id;
partyListArray[indxAttendees].name = toParty[indxAttendees].name;
partyListArray[indxAttendees].entityType = toParty[indxAttendees].entityType;
}
}
Xrm.Page.getAttribute("to").setValue(null);
Xrm.Page.getAttribute("to").setValue(partyListArray);
Instead of creating a whole new array, you can delete what you want from the array itself. Try this:
var emails = [{email: "add1#domain.com"}, {email: "add2#domain.com"}, {email: "address#toBe.Removed"}, {email: "add3#domain.com"}, {email: "add4#domain.com"}];
var removeIndex = emails.map(function(item) { return item.email; }).indexOf("address#toBe.Removed");
removeIndex > -1 && emails.splice(removeIndex, 1);

In Firebase when using push() How do I pull the unique ID

I'm attempting to add/remove entries from a Firebase database. I want to list them in a table to be added/modified/removed (front end) but I need a way to uniquely identify each entry in order to modify/remove. Firebase adds a unique identifier by default when using push(), but I didn't see anything referencing how to select this unique identifier in the API documentation. Can this even be done? Should I be using set() instead so I'm creating the unique ID?
I've put this quick example together using their tutorial:
<div id='messagesDiv'></div>
<input type='text' class="td-field" id='nameInput' placeholder='Name'>
<input type='text' class="td-field" id='messageInput' placeholder='Message'>
<input type='text' class="td-field" id='categoryInput' placeholder='Category'>
<input type='text' class="td-field" id='enabledInput' placeholder='Enabled'>
<input type='text' class="td-field" id='approvedInput' placeholder='Approved'>
<input type='Button' class="td-field" id='Submit' Value="Revove" onclick="msgRef.remove()">
<script>
var myDataRef = new Firebase('https://unique.firebase.com/');
$('.td-field').keypress(function (e) {
if (e.keyCode == 13) {
var name = $('#nameInput').val();
var text = $('#messageInput').val();
var category = $('#categoryInput').val();
var enabled = $('#enabledInput').val();
var approved = $('#approvedInput').val();
myDataRef.push({name: name, text: text, category: category, enabled: enabled, approved: approved });
$('#messageInput').val('');
}
});
myDataRef.on('child_added', function(snapshot) {
var message = snapshot.val();
displayChatMessage(message.name, message.text, message.category, message.enabled, message.approved);
});
function displayChatMessage(name, text, category, enabled, approved, ) {
$('<div/>').text(text).prepend($('<em/>').text(name+' : '+category +' : '+enabled +' : '+approved+ ' : ' )).appendTo($('#messagesDiv'));
$('#messagesDiv')[0].scrollTop = $('#messagesDiv')[0].scrollHeight;
};
</script>
Now lets assume I have three rows of data:
fred : 1 : 1 : 1 : test message 1
fred : 1 : 1 : 1 : test message 2
fred : 1 : 1 : 1 : test message 3
How do I go about uniquely identifying row 2?
in the Firebase Database they look like this:
-DatabaseName
-IuxeSuSiNy6xiahCXa0
approved: "1"
category: "1"
enabled: "1"
name: "Fred"
text: "test message 1"
-IuxeTjwWOhV0lyEP5hf
approved: "1"
category: "1"
enabled: "1"
name: "Fred"
text: "test message 2"
-IuxeUWgBMTH4Xk9QADM
approved: "1"
category: "1"
enabled: "1"
name: "Fred"
text: "test message 3"
To anybody finding this question & using Firebase 3+, the way you get auto generated object unique ids after push is by using the key property (not method) on the promise snapshot:
firebase
.ref('item')
.push({...})
.then((snap) => {
const key = snap.key
})
Read more about it in the Firebase docs.
As a side note, those that consider generating their own unique ID should think twice about it. It may have security and performance implications. If you're not sure about it, use Firebase's ID. It contains a timestamp and has some neat security features out of the box.
More about it here:
The unique key generated by push() are ordered by the current time, so the resulting list of items will be chronologically sorted. The keys are also designed to be unguessable (they contain 72 random bits of entropy).
To get the "name" of any snapshot (in this case, the ID created by push()) just call name() like this:
var name = snapshot.name();
If you want to get the name that has been auto-generated by push(), you can just call name() on the returned reference, like so:
var newRef = myDataRef.push(...);
var newID = newRef.name();
NOTE:
snapshot.name() has been deprecated. See other answers.
snapshot.name() has been deprecated. use key instead. The key property on any DataSnapshot (except for one which represents the root of a Firebase) will return the key name of the location that generated it. In your example:
myDataRef.on('child_added', function(snapshot) {
var message = snapshot.val();
var id = snapshot.key;
displayChatMessage(message.name, message.text, message.category, message.enabled, message.approved);
});
To get uniqueID after push() you must use this variant:
// Generate a reference to a new location and add some data using push()
var newPostRef = postsRef.push();
// Get the unique key generated by push()
var postId = newPostRef.key;
You generate a new Ref when you push() and using .key of this ref you can get uniqueID.
As #Rima pointed out, key() is the most straightforward way of getting the ID firebase assigned to your push().
If, however, you wish to cut-out the middle-man, Firebase released a gist with their ID generation code. It's simply a function of the current time, which is how they guarantee uniqueness, even w/o communicating w/ the server.
With that, you can use generateId(obj) and set(obj) to replicate the functionality of push()
Here's the ID function:
/**
* Fancy ID generator that creates 20-character string identifiers with the following properties:
*
* 1. They're based on timestamp so that they sort *after* any existing ids.
* 2. They contain 72-bits of random data after the timestamp so that IDs won't collide with other clients' IDs.
* 3. They sort *lexicographically* (so the timestamp is converted to characters that will sort properly).
* 4. They're monotonically increasing. Even if you generate more than one in the same timestamp, the
* latter ones will sort after the former ones. We do this by using the previous random bits
* but "incrementing" them by 1 (only in the case of a timestamp collision).
*/
generatePushID = (function() {
// Modeled after base64 web-safe chars, but ordered by ASCII.
var PUSH_CHARS = '-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz';
// Timestamp of last push, used to prevent local collisions if you push twice in one ms.
var lastPushTime = 0;
// We generate 72-bits of randomness which get turned into 12 characters and appended to the
// timestamp to prevent collisions with other clients. We store the last characters we
// generated because in the event of a collision, we'll use those same characters except
// "incremented" by one.
var lastRandChars = [];
return function() {
var now = new Date().getTime();
var duplicateTime = (now === lastPushTime);
lastPushTime = now;
var timeStampChars = new Array(8);
for (var i = 7; i >= 0; i--) {
timeStampChars[i] = PUSH_CHARS.charAt(now % 64);
// NOTE: Can't use << here because javascript will convert to int and lose the upper bits.
now = Math.floor(now / 64);
}
if (now !== 0) throw new Error('We should have converted the entire timestamp.');
var id = timeStampChars.join('');
if (!duplicateTime) {
for (i = 0; i < 12; i++) {
lastRandChars[i] = Math.floor(Math.random() * 64);
}
} else {
// If the timestamp hasn't changed since last push, use the same random number, except incremented by 1.
for (i = 11; i >= 0 && lastRandChars[i] === 63; i--) {
lastRandChars[i] = 0;
}
lastRandChars[i]++;
}
for (i = 0; i < 12; i++) {
id += PUSH_CHARS.charAt(lastRandChars[i]);
}
if(id.length != 20) throw new Error('Length should be 20.');
return id;
};
})();
You can update record adding the ObjectID using a promise returned by .then() after the .push() with snapshot.key:
const ref = Firebase.database().ref(`/posts`);
ref.push({ title, categories, content, timestamp})
.then((snapshot) => {
ref.child(snapshot.key).update({"id": snapshot.key})
});
If you want to get the unique key generated by the firebase push() method while or after writing to the database without the need to make another call, here's how you do it:
var reference = firebaseDatabase.ref('your/reference').push()
var uniqueKey = reference.key
reference.set("helllooooo")
.then(() => {
console.log(uniqueKey)
// this uniqueKey will be the same key that was just add/saved to your database
// can check your local console and your database, you will see the same key in both firebase and your local console
})
.catch(err =>
console.log(err)
});
The push() method has a key property which provides the key that was just generated which you can use before, after, or while you write to the database.
Use push() to get a new reference and key to get the the unique id of the it.
var ref = FirebaseDatabase.instance.ref();
var newRef = ref.push(); // Get new key
print(newRef.key); // This is the new key i.e IqpDfbI8f7EXABCma1t
newRef.set({"Demo": "Data"}) // Will be set under the above key
How i did it like:
FirebaseDatabase mFirebaseDatabase = FirebaseDatabase.getInstance();
DatabaseReference ref = mFirebaseDatabase.getReference().child("users").child(uid);
String key = ref.push().getKey(); // this will fetch unique key in advance
ref.child(key).setValue(classObject);
Now you can retain key for further use..

Categories

Resources