Value in local storage replaced instead of updated - javascript

I have made this phone book site where it stores for now the name and the phone number of the user.
Now I have hit a wall where if I insert the user data (name and phone number) it pushes it to the phone book array and when I try to push another user it replaces the first one instead of updating the array.
This is my JavaScript code:
"use strict";
let myStorage = window.localStorage;
function showOverlay(showButton, showContainer) { // this whole funciton opens up the overlay
const addButton = document.querySelector("." + showButton);
addButton.addEventListener("click", function addSomthing() {
document.querySelector("." + showContainer).style.display = 'block';
});
}
showOverlay("addBtn", "formContainer");
function cancelOverlay(cancelButton, showContainer) { //this dynamic funciton helps with closing overlays after we are done with the event
const removeOverlay = document.querySelector("." + cancelButton);
removeOverlay.addEventListener("click", function removeSomthing() {
document.querySelector("." + showContainer).style.display = 'none';
});
}
cancelOverlay("cancelOverlay", "formContainer");
function inputAndOutput() {
cancelOverlay("submitButton", "formContainer"); //this function helps me close the form window after i click on send
const form = document.getElementById("addForm");
form.addEventListener("submit", (e) => { //this is a submit event when the send button is pressed it makes an object and with the help of JSON it puts it into an array
let formOutput = {
name: document.getElementById("name").value,
phoneNumber: document.getElementById("phone").value
} //end of form
myStorage.setItem("formOutput", JSON.stringify(formOutput)); //array of obj
console.log(myStorage.getItem('formOutput')); //testing
displayOutput();
e.preventDefault(); //prevent the page to reload
} //end of Event
, );
}
inputAndOutput();
let phoneArray = [100];
function displayOutput() {
if (myStorage.getItem('formOutput')) {
let { name, phoneNumber } = JSON.parse(myStorage.getItem('formOutput'));
const output = document.getElementById("outPutContainer");
phoneArray.push(output.innerHTML =
`
<ul>
<li>${name} </li>
<li>${phoneNumber} </li>
</ul>
<br>
`);
}
}

As you are submitting the form you are just replacing the localstorage item with the new one instead of that you will have to take the value from the storage store it in a variable and then add the new values to the same variable and push that variable to the storage.
some what like this:
form.addEventListener("submit", (e) => { //this is a submit event when the send button is pressed it makes an object and with the help of JSON it puts it into an array
let formOutput = {
name: document.getElementById("name").value,
phoneNumber: document.getElementById("phone").value
} //end of form
//HERE
const oldData = JSON.parse(myStorage.getItem("formOutput"));
oldData.push(formOutput); // I believe its an array
myStorage.setItem("formOutput", JSON.stringify(oldData)); //array of obj
console.log(myStorage.getItem('formOutput')); //testing
displayOutput();
e.preventDefault(); //prevent the page to reload
} //end of Event
, );

Related

Required Field Validation error not displaying for fields added into Array

I am trying to add the fields in the form through Observable Array in the KnockoutJS to repeat the same section of fields. But the issue is the Required Field Validation errors are not displaying for the fields that are added through the Observable Array.
Below is what I am trying
var orfViewModel = function () {
var self = this;
self.currentPage = ko.observable(1);
self.referringPage = ko.observable();
self.StrainDetails = ko.observableArray();
self.koArrayErrors = ko.validation.group(self.StrainDetails(), {
deep: true,
live: true });
self.addStrain = function () {
self.StrainDetails.push(new StrainVM());
}
self.remove = function (item) {
self.StrainDetails.remove(item);
};
I added the self.koArrayErrors validation errors within the array. So when a next button on page is clicked I am expecting to see the field required error message on the required fields.
Below is the next button logic
self.next = function () {
self.errors = ko.validation.group(this);
console.log(self.errors().length);
if (self.errors().length != 0) {
self.errors.showAllMessages();
self.koArrayErrors.showAllMessages();
}
if (!formIsValid('Page_' + self.currentPage())) {
$(window).scrollTop(0);
return false;
}
if (self.referringPage() != null) {
self.currentPage(self.referringPage());
self.referringPage(null);
} else {
self.currentPage(self.currentPage() + 1);
}
self.gotoPage();
};
self.gotoPage = function () {
$("div[id^='Page_']").hide();
$("div[id^='Page_" + this.currentPage() + "']").show();
$(window).scrollTop(0);
self.errors.showAllMessages(false);
self.koArrayErrors.showAllMessages(false);
};
Below is the StrainVM() which pushes the data in to the Observable array like
function StrainVM() { var self = this;
self.pdtNeeded = ko.observable().extend({ required: { params: true, message: "Required! Please sect Pdt Needed" } });
ko.validation.registerExtenders();
Even though I don't enter anything for pdtNeeded field, clicking on the Next button does not take me to next page and does not show the error Required! Please sect Pdt Needed next to field.
Users will not know what is not letting them to hit the next page.
How can I handle the validation here that is added to Observable array?

How to store jQuery objects locally using localStorage?

I'm trying to build a to-do list app (beginner here), and have some difficulties in storing the values inputted so that I can store this locally, so once the page is reloaded, it's still saved. You input an item and it gets stored in task, and then it's checked if it's deleted or checked-off, and I think appended to an array, so I'm not sure if I should be iterating over this. Here is the code: (Thank you in advance!)
$(".txtb1").on("keyup", function (e) {
console.log("sdfsdfsd");
//13 means enter button
if (e.keyCode === 13 && $(".txtb1").val() != "") {
console.log("entered");
var task = $("<div class='task'></div>").text($(".txtb1").val());
var del = $("<i class='fas fa-trash-alt'></i>").click(function () {
var p = $(this).parent();
p.fadeOut(function () {
p.remove();
});
});
var check = $("<i class='fas fa-check'></i>").click(function () {
var p = $(this).parent();
p.fadeOut(function () {
$("#task2.comp").append(p);
/* No stupid appendChild */
p.fadeIn();
});
$(this).remove();
});
task.append(del, check);
$("#task1.notcomp").append(task);
//to clear the input
$(".txtb1").val("");
//task needs to be set
localStorage.setItem('task', task.text());
var data = localStorage.getItem('task');
localStorage.removeItem('$task');
/* ------------------------ */
//Other option: Store data
localStorage.setItem('task1', JSON.stringify(task));
//Get data
var data = JSON.parse(localStorage.getItem('task1'));
//Remove data
localStorage.removeItem('task1');
}
}

Is there a way to catch an onchange trigger with a focusout by a button click?

The scenario is this modal window:
The inputs 2, 3 and 4 with an .on('change', function () {}); makes an AJAX call to a specified controller, that update the recod values and reload the value 1.
So the right, but not functional way is to:
click the input 1 and set the value
focusout it by clicking outside the input
AJAX reload value 1 updated
click input 2 and set the value
focus out it by clicking outside the input
AJAX reload value 1 updated
The user click confirm that call another controller that make some checks and change the status of an object (from Draft to Confirmed)
The problem
If I try this way:
click the input 1 and set the value
focusout it by clicking outside the input
AJAX reload value 1 updated
click input 2 and set the value
Click confirm button that call another controller and trigger the input change
Now, with this way the problem occurs because the confirm method doesn't receive yet the update from last onchange trigger and the check is not correct.
Is there a way to manage multiple AJAX from different triggers like onchange and onclick?
Something like if the below onclick is triggered:
// Trigger for button confirm inside timesheet sheet modal
$(document).on('click', 'button.js_confirm_timesheet_sheet', function (ev) {
var $button = $(this);
var wizard_id = $button.data()['wizardId'];
var sheet_id = $button.data()['sheetId'];
var values = {
'wizard_id': wizard_id,
'sheet_id': sheet_id,
};
confirm_sheet_distribution_hours(values);
});
Check if the click come from an input focus out, if yes trigger the onchange first and after the onclick
Maybe this solution can be a bad way to do this.
Little, triggers recap:
The inputs have an onchange trigger that writes data to backend object with an AJAX call that recompute values and return the new one
The confirm button check if everything is ok with an AJAX call and change the backend object status
The other workaround maybe can be to declare an object that keeps track of each changed input boxes and clear it on each AJAX success return.
Something like:
var changedData = {};
function update_wizard_data_and_modal(values, $input_elem, event) {
changedData[key] = $input_elem;
ajax.jsonRpc("/my/controller/path", "call", values)
.then(function (new_modal_values) {
$input_elem.removeClass('input-value-error');
if (!jQuery.isEmptyObject(new_modal_values)) {
if (new_modal_values.error_msg) {
var $content = $(new_modal_values.error_msg);
$content.modal({
backdrop: 'static',
keyboard: false
});
$content.appendTo('body').modal();
// Show error class
$input_elem.val('00:00');
$input_elem.addClass('input-value-error');
}
// Update the header values with hours to be distribuited
$('#header-wizard-values').html(new_modal_values.header_values);
// Update the hours to get payed available
$('.js_hours_to_get_payed').html(new_modal_values.hours_get_payed_values);
// Clear the changedData object
for (var member in changedData) delete changedData[member];
}
});
}
function confirm_sheet_distribution_hours(values) {
if jQuery.isEmptyObject(changedData){
ajax.jsonRpc("/confirm/controller/path", "call", values)
.then(function (response) {
if ('error' in response) {
//response in this case is the modal error template
$(response.error).appendTo('body').modal();
} else {
// Close modal and refresh the grid for current period
$('#modal_timesheet_sheet_confirm').modal('hide');
var sheet_item_data = {
'year': response.year,
'month': response.month,
};
update_grid_and_bars_values(sheet_item_data);
}
});
} else {
// TODO: trigger the change for element inside object and confirm
}
}
$(document).on("change", "input.distribution-input", function (ev) {
var $input = $(this);
var sheet_id = $('input[name="sheet_id"]').val();
var wiz_line_id = Number($input.attr('id').match(/\d+/)[0]);
var row_wizard_data = $input.closest('div.row').data();
var leave_type_id = row_wizard_data['leaveTypeId'];
var wizard_id = row_wizard_data['wizardId'];
var values = {
'sheet_id': Number(sheet_id),
'wizard_id': wizard_id,
'wiz_line_id': wiz_line_id,
'leave_type_id': leave_type_id,
'input_value': $input.val(),
};
var is_good_formatted = check_string_time_format($input, {});
if (is_good_formatted) {
update_wizard_data_and_modal(values, $input, ev);
}
});
// Trigger for button confirm inside timesheet sheet modal
$(document).on('click', 'button.js_confirm_timesheet_sheet', function (ev) {
ev.preventDefault();
ev.stopPropagation();
var $button = $(this);
var wizard_id = $button.data()['wizardId'];
var sheet_id = $button.data()['sheetId'];
var values = {
'wizard_id': wizard_id,
'sheet_id': sheet_id,
};
confirm_sheet_distribution_hours(values);
});
As suggested by Taplar I used a similar approach.
Here the javascript that manages the "onchange" of a wizard in the Odoo Frontend.
// Variable used for the last input changed when user click the Confirm button
var canConfirm = true;
/* Variable used for keep trace of the number of retry inside method
* confirm_sheet_distribution_hours
* */
var nr_of_try = 0;
function update_wizard_data_and_modal(values, $input_elem, event) {
if (event.type !== 'input') {
ajax.jsonRpc("/controller/path/...", "call", values)
.then(function (new_modal_values) {
canConfirm = true;
$input_elem.removeClass('input-value-error');
if (!jQuery.isEmptyObject(new_modal_values)) {
if (new_modal_values.error_msg) {
var $content = $(new_modal_values.error_msg);
$content.modal({
backdrop: 'static',
keyboard: false
});
$content.appendTo('body').modal();
// Show error class
$input_elem.val('00:00');
$input_elem.addClass('input-value-error');
}
// Update the header values with hours to be distribuited
$('#header-wizard-values').html(new_modal_values.header_values);
// Update the hours to get payed available
$('.js_hours_to_get_payed').html(new_modal_values.hours_get_payed_values);
}
});
} else {
canConfirm = false;
}
}
function set_the_amount_on_wizard($input, values, event) {
if (event.type !== 'input') {
ajax.jsonRpc("/controller/path/...", "call", values)
.then(function (response) {
canConfirm = true;
if ('error' in response) {
//response in this case is the modal error template
$(response.error).appendTo('body').modal();
// Reset input value (backend reset the TransientModel value)
$input.val('00:00')
}
});
} else {
canConfirm = false;
}
}
function confirm_sheet_distribution_hours(values) {
if (canConfirm) {
ajax.jsonRpc("/controller/patH/...", "call", values)
.then(function (response) {
if ('error' in response) {
//response in this case is the modal error template
$(response.error).appendTo('body').modal();
} else {
// Close modal and refresh the grid for current period
$('#modal_timesheet_sheet_confirm').modal('hide');
var sheet_item_data = {
'year': response.year,
'month': response.month,
};
update_grid_and_bars_values(sheet_item_data);
}
});
} else {
/*Try six times to confirm the sheet (Until the onchange doesn't write
* new values the AJAX call doesn't set canConfirm as True
* */
if (nr_of_try <= 5) {
setTimeout(function () {
nr_of_try++;
confirm_sheet_distribution_hours(values);
}, 500);
}
}
}
//Trigger that monitorate hours distribution change
$(document).on("input change", "input.distribution-input", function (ev) {
var $input = $(this);
var sheet_id = $('input[name="sheet_id"]').val();
var wiz_line_id = Number($input.attr('id').match(/\d+/)[0]);
var row_wizard_data = $input.closest('div.row').data();
var leave_type_id = row_wizard_data['leaveTypeId'];
var wizard_id = row_wizard_data['wizardId'];
var values = {
'sheet_id': Number(sheet_id),
'wizard_id': wizard_id,
'wiz_line_id': wiz_line_id,
'leave_type_id': leave_type_id,
'input_value': $input.val(),
};
var is_good_formatted = check_string_time_format($input);
if (is_good_formatted) {
update_wizard_data_and_modal(values, $input, ev);
}
});
//Trigger that monitorate hours distribution change
$(document).on("input change", "input.payment-hour-input", function (ev) {
var $input = $(this);
var row_wizard_data = $input.closest('div.row').data();
var wizard_id = row_wizard_data['wizardId'];
var values = {
'wizard_id': wizard_id,
'input_value': $input.val(),
};
var is_good_formatted = check_string_time_format($input);
if (is_good_formatted) {
set_the_amount_on_wizard($input, values, ev);
}
});
// Trigger for button confirm inside timesheet sheet modal
$(document).on('click', 'button.js_confirm_timesheet_sheet', function (ev) {
var $button = $(this);
var wizard_id = $button.data()['wizardId'];
var sheet_id = $button.data()['sheetId'];
var values = {
'wizard_id': wizard_id,
'sheet_id': sheet_id,
};
// Variable used for retry sheet confirmation until canConfirm is not True
// Max repeat call is 6 times
nr_of_try = 0;
confirm_sheet_distribution_hours(values);
});
In simple words.
When the user is typing on inputs boxes the type input inside on.() set the variable canConfirm to false.
This prevents case when user changes values and click to the Confirm buttons immediately after.
In fact if the user changes some input box and immediately click "Confirm" the AJAX call starts only if the flag is true, if not the method calls it's self six times every 500 ms.
Let me know if there is some better way to doing that.
Thanks
PS: I will try a better approach with a DTO backend that clone data from model and manage updates like onchange cache.
Inspired by: https://python-3-patterns-idioms-test.readthedocs.io/en/latest/Messenger.html

how to get a reference number (form of a link) to auto fill part of a form in another html page using javascript

using local storage and onclick with javascript
I have a html file with 2 job descriptions :
html file 1
<li><Job Reference Number: wru01</li>
<li><Job Reference Number: wru01</li>
I need to create a link (using javascript) that when each job description is clicked it auto fills out the form where the job description should be entered (this form is on another html page)
html file 2:
<legend>Job Application Information: </legend>
<label> Job Reference Number: </label>
<input id="refnumber" type="text" name="refnumber" required="required" />
so basically i need it that, when, and depending on which job number is clicked wru01 or wru02, it auto fills the job reference number in the form on the next page using local storage.
I have already tried this
js file 1
function onclick1() {
var anchor = document.getElementById('link');
anchor.addEventListener('click', function(event) {
event.preventDefault();
const jobCode = event.target.getAttribute('data-job');
localStorage.setItem('job-code', jobCode);
//need redirect user to apply page
//console.log(event.target)
window.location = event.target.getAttribute('href');
})
}
function onclick2() {
var anchor = document.getElementById('link2');
anchor.addEventListener('click', function(event) {
event.preventDefault();
const jobCode = event.target.getAttribute('data-job');
localStorage.setItem('job-code', jobCode);
//need redirect user to apply page
//console.log(event.target)
window.location = event.target.getAttribute('href');
})
}
function init() {
document.getElementById("link").onclick = function() {
onclick1()
};
document.getElementById("link2").onclick = function() {
onclick2()
}
window.onload = init;
}
js file 2
function LoadJobCode() {
var code = localStorage.getItem('job-code');
if (code) {
var input = document.getElementById('refnumber');
// disable text being entered
input.value = code;
input.disabled = true;
}
}
Excuse me,that's not a good idea to do it.I think you can use setTimeout to solve the problem.that's my code:
function onclick1() {
var anchor = document.getElementById('link');
anchor.addEventListener('click', function (event) {
event.preventDefault();
const jobCode = event.target.getAttribute('data-job');
console.log(jobCode)
localStorage.setItem('job-code', jobCode);
setTimeout(() => {
window.location.href = event.target.getAttribute('href');
},1000)
})
}
why did I do that?That's order to make sure to save the data(data-job) before entering another html page.Likewise,you can use async/await,such as below:
function onclick1() {
var anchor = document.getElementById('link');
anchor.addEventListener('click', function (event) {
event.preventDefault();
const jobCode = event.target.getAttribute('data-job');
console.log(jobCode)
localStorage.setItem('job-code', jobCode);
async function locate() {
await new Promise(() => {
window.location.href = event.target.getAttribute('href');
})
}
locate();
})
}

localStorage clears on refresh, parse & stringify not working

Working on a practice app with localStorage, but the stored data is getting cleared on page refresh. Based on answers to similar questions, I've used JSON.stringify(); on setItem, and JSON.parse(); on getItem, but still no luck. Am I using those methods in the wrong way? For reference, #petType and #petName are input IDs, and #name and #type are ul IDs. Thanks!
var animalArray = [];
var addPet = function(type,name) {
var type = $("#petType").val();
var name = $("#petName").val();
localStorage.setItem("petType", JSON.stringify(type));
localStorage.setItem("petName", JSON.stringify(name));
animalArray.push(type,name);
};
var logPets = function() {
animalArray.forEach( function(element,index) {
//empty array
animalArray.length = 0;
//empty input
$("input").val("");
var storedName = JSON.parse(localStorage.getItem("petName"));
var storedType = JSON.parse(localStorage.getItem("petType"));
//append localStorage values onto ul's
$("#name").append("<li>" + storedName + "</li>");
$("#type").append("<li>" + storedType + "</li>");
});
};
//click listPets button, call logPets function
$("#listPets").on("click", function() {
logPets();
$("#check").html("");
});
//click enter button, call addPet function
$("#enter").on("click", function() {
addPet(petType,petName);
$("#check").append("<i class='fa fa-check' aria-hidden='true'></i>");
});
It appears to clear because you are not loading data from it when the page loads. There are multiple bugs in the code:
It appears that you're only saving the last added pet to localStorage, which would create inconsistent behaviour
Setting animalArray.length to 0 is incorrect
animalArray.push(type, name); is probably not what you want, since it adds 2 items to the array, do something like animalArray.push({type: type, name: name});
logPets can just use the in memory array, since it's identical to the one saved
Fixed code:
var storedArray = localStorage.getItem("animalArray");
var animalArray = [];
if(storedArray) {
animalArray = JSON.parse(storedArray);
}
var addPet = function(type,name) {
var type = $("#petType").val();
var name = $("#petName").val();
animalArray.push({type: type, name: name});
localStorage.setItem("animalArray", JSON.stringify(animalArray));
};
var logPets = function() {
animalArray.forEach( function(element,index) {
//empty input
$("input").val("");
//append localStorage values onto ul's
$("#name").append("<li>" + element.name + "</li>");
$("#type").append("<li>" + element.type + "</li>");
});
};
//click listPets button, call logPets function
$("#listPets").on("click", function() {
logPets();
$("#check").html("");
});
//click enter button, call addPet function
$("#enter").on("click", function() {
addPet(petType,petName);
$("#check").append("<i class='fa fa-check' aria-hidden='true'></i>");
});
A quick fiddle to demo it: https://jsfiddle.net/rhnnvvL0/1/

Categories