Pre-fill form with local storage - javascript

I'm loading questions from a JSON into my EJS template and want to populate each field from localStorage. The following saves the last value of each dropdown, text, and slider element:
var select = document.getElementsByTagName('select');
for (var i = 0; i < select.length; i++){
select[i].value = localStorage.getItem(i);
}
jQuery("select").change(function () {
for (var i = 0; i < select.length; i++){
localStorage.setItem(i, select[i].value);
}
});
I repeat this for all "input" tags. The issue is that the select values also get passed into text and slider — and vice versa (i.e. if I enter values for text and slider, they overwrite the select values, except they are left blank).
My end goal is to save each form-fields' most recent value so that my entries are not lost when I refresh the page.

It would be a lot more elegant to create a single localStorage entry representing your saved values, rather than pollute LS with many entries for each field. I would recommend something like this:
function save() {
const selects = document.querySelectorAll('select');
// select other element types
// ...
const selectValues = [...selects].map(select => select.value);
const textValues = [...textInputs].map(textInput => textInput.value);
const sliderValues = [...sliderInputs].map(sliderInput => sliderInput.value);
const savedObj = { selectValues, textValues, sliderValues };
localStorage.savedFormValues = JSON.stringify(savedObj);
}
That way, you only create a single entry in localStorage, and each entry type is quite distinct. Then, to get the values, just do the same thing in reverse:
function populate() {
const selects = document.querySelectorAll('select');
// ...
const { selectValues, textValues, sliderValues } = JSON.parse(localStorage.savedFormValues);
selectValues.forEach((selectValue, i) => selects[i].value = selectValue);
// ...

Related

Javascript, make a variable inside a function globally available

this application has 2 select functions, the first select function takes data from a json file. when one is selected it saves the ID in a variable. this variable is created using let outside the function. in the second select function it takes data from a json file and only shows the data where the ID from the json matches the ID saved in the first select variable.
The problem is that the variable cant be found outside of the function. when i console the variable outside the function it came back undefined
I tried changing the variable from let to var. this didn't work. i expected it to be solved but instead there didn't happen anything diffrent.
let locID;
let select;
let select2;
function preload() {
data = loadJSON(
"https://raw.githubusercontent.com/mia-mmt2-2223/leesfestival/main/festival.json"
);
}
function setup() {
createCanvas(400, 400);
//LOCATION SELECTION
//create select element with as options name from locations from json
select = createSelect();
select.position(10, 10);
select.option("Select a location");
for (let i = 0; i < data.locations.length; i++) {
select.option(data.locations[i].name);
}
//when a location is selected, save the location id
select.changed(function () {
item = select.value();
for (let i = 0; i < data.locations.length; i++) {
if (data.locations[i].name == item) {
locID = data.locations[i].id;
}
}
});
//WORKSHOP SELECTION
//create select element with as options name from workshops where location matches locID from json
select2 = createSelect();
select2.position(10, 50);
select2.option("Select a workshop");
for (let i = 0; i < data.workshops.length; i++) {
if (data.workshops[i].location == locID) {
select2.option(data.workshops[i].name);
}
}
}````

Push all objects after a selected object into an array

I have a web page that returns a list of objects like:
date.pdf
names.csv
address.pdf
age.csv
cost.csv
budget.csv
data.pdf
race.pdf
contractors.csv
When a user checks budget.csv, I want every object with the .csv extension from that point to be pushed into csv_files[]. If they select names.csv, then every .csv including and after names is pushed into the array.
So the only data that gets pushed into the array is from the selected object downwards. How can I implement this?
Current code
const csv_files = []
$scope.listAllobjects = (err, data) => {
$.each(data.Contents, (index, value) => {
if (value.Key.endsWith("csv")) {
csv_files = [];
}
// Handle click on selection checkbox
$("#filesobjects-table tbody").on("click", 'input[type="checkbox"]', (e1) => {
const checkbox = e1.currentTarget;
const $row = $(checkbox).closest("tr");
const data = $tb.DataTable().row($row).data();
let index = -1;
// Prevent click event from propagating to parent
e1.stopPropagation();
// Find matching key in currently checked rows
index = $scope.view.keys_selected.findIndex((e2) => e2.Key === data.Key);
if (checkbox.checked && data.Key.endsWith("csv")) {
console.log(selected csv)
}
});
}
There's a few ways, I suppose, to approach this problem, but the most intuitive to me is this:
const csvList = ["date.pdf","names.csv","address.pdf","age.csv","cost.csv","budget.csv","data.pdf","race.pdf","contractors.csv"];
const selectedCsv = 'budget.csv';
function getCsvsAfter(csvList, selectedCsv) {
const filteredCsvs = [];
let found = false;
for (let csv of csvList) {
if (csv === selectedCsv) found = true;
if (found) filteredCsvs.push(csv);
}
return filteredCsvs;
}
console.log(getCsvsAfter(csvList, selectedCsv));
Iterate over every csv, and when you've hit the one you're trying to match, set a variable called found to true. Once it's true, you can add every following csv onto the list.
const list = ['date.pdf','names.csv','address.pdf','age.csv','cost.csv','budget.csv','data.pdf','race.pdf','contractors.csv'];
const selected = 'budget.csv'
const csv_files = list.slice(list.indexOf(selected))
console.log(csv_files)
Here you go with a pure JavaScript solution (Descriptive comments has been added in the below code snippet).
var contentData = ["date.pdf", "names.csv", "address.pdf", "age.csv", "cost.csv", "budget.csv", "data.pdf", "race.pdf", "contractors.csv"];
var myDiv = document.getElementById("cboxes");
for (var i = 0; i < contentData.length; i++) {
var checkBox = document.createElement("input");
var label = document.createElement("label");
checkBox.type = "checkbox";
checkBox.value = contentData[i];
myDiv.appendChild(checkBox);
myDiv.appendChild(label);
label.appendChild(document.createTextNode(contentData[i]));
}
// Event to handle the checkbox click
document.getElementById('getResult').addEventListener('click', () => {
document.getElementById('showResult').innerHTML = getCheckedValues();
});
function getCheckedValues() {
// filtered out the checked items.
const element = Array.from(document.querySelectorAll('input[type="checkbox"]'))
.filter((checkbox) => checkbox.checked).map((checkbox) => checkbox.value);
// element[0] will always return the first checked element and then we are getting index of that.
const checkedElemIndex = contentData.indexOf(element[0]);
// Slice the content data to get the elements from the checked element index.
return contentData.slice(checkedElemIndex, contentData.length)
}
<div id="cboxes"></div>
<button id="getResult">Get Result</button>
<pre id="showResult"></pre>

Reusing function within different functions (new array from each) - javascript

Have an array which is being compiled based on user input selection (checkbox and radio buttons)
This is being compiled using an input on change function.
The array is then used to check if values in the array match data attributes referenced within each card, and those which match, show the respective card.
This is working fine.
I am now trying to get the same functionality, but instead of being based on user input, the result is being compiled based on user query string (string is also compiled from the user input - effectively saving a query for using to return to page with results without having to enter the checkbox values again). This function has a lot of if true, push which I would like to re-use instead of re-write. I have simplified here.
Problem I am having is using the same function I built for show/hide the card based on user input with the query string.
// Set Globals:
var arr = []
function buildResults() {
// Build query based on input values and push into array:
$("input").on("change", function() {
var arr = [];
$(":checkbox").each(function() {
if ($(this).is(":checked")) {
arr.push($(this).val());
}
});
$(":radio").each(function() {
if ($(this).is(":checked")) {
arr.push($(this).val());
}
});
console.log(arr);
// Join array using unique string
var vals = arr.join("--");
// Set URL to pin query to and begin pushing values to string:
var urlBegin = "https://thisisatest/?results=";
var str = vals;
$("#val").text(urlBegin + vals);
$("#query").text(vals);
$("#copyTarget").val(urlBegin + vals);
userSelection = arr;
resRec();
});
}
buildResults();
function resRec() {
// Show div based on user checkbox values:
var user = userSelection;
var dataRec = [];
var recordResultCount = 0;
console.log(user);
var first = user.includes("123");
if (first == true) {
dataRec.push(123456);
}
var recordResults = [...new Set(dataRec)];
recordResultCount = recordResults.length;
console.log(recordResultCount);
// Show only the records needed:
$(".card").each(function() {
var recordFound = $.inArray($(this).data("recordid"), dataRec);
if (recordFound === -1) {
$(this).parent().addClass("destroy");
} else {
$(this).removeClass("destroy");
}
});
}
function resQuery() {
var urlQuery = window.location.href.match(/results=(.+)/)[1];
console.log(urlQuery);
user = urlQuery;
}
// If user enters page via unique query only, and not from page start:
$(function() {
if (window.location.pathname == "https://thisisatest/?results=") {
// reuse resRec() here, but using urlQuery and not userSelection;
var user = resQuery();
resRec();
// and show only the cards which match the results built from query
}
});
resQuery();
Function reuse is still new to me, and while I think my logic is on the correct path, I am still getting resRec() not defined.
Thank you.

array variable to also update when an element is deleted in ReactJS

I have the following code below
const myID = [] //global variable
const tableContents = () = {
const [selectedOptions, setSelectedOptions] = useState([])
const doChange = (selectedOptions) => {
setSelectedOptions([...selectedOptions])
for (var i = 0; i < Object.keys(selectedOptions).length; i++) {
myID[i] = selectedOptions[i].id
}
}
}
console.log(myID)
The function doChange is triggered by onChange of a component (Filter button) that has options. Each of the options has an id. What I initially wanted to do is put the id's of the chosen options in an array so that I can pass it as a value of a query. The problem is when I choose multiple options and remove one, the array that displays still includes the id of the deleted option.
For example:
Chosen options are option1, option2, option3. When console.log(myID) is executed, 1,2,3 would appear. When I remove option3, the same 1,2,3 would still appear. How do I structure the code wherein when I remove an option, the array displayed will also be updated?

Get and set object values in localStorage array

I'm trying to set objects into localStorage with a format similar to the following:
[{"1":{"property1":false,"property2":false}},{"2":{"property1":false,"property2":false}}]
Where I'd be able to set the 1 or 2 based on a dynamic value I'm getting from a REST call. What I have so far is:
// check if session exists and create if not
var StorageObject = JSON.parse(localStorage.getItem("session")) || [];
//see if the current id from the REST call is in storage and push with properties if not
if ( !StorageObject[thisItemsListID] ) {
var itemProperties = {};
itemProperties[thisItemsListID] = {};
itemProperties[thisItemsListID]["property1"] = false;
itemProperties[thisItemsListID]["property2"] = false;
StorageObject.push(itemProperties);
localStorage.setItem('session', JSON.stringify(StorageObject));
}
I can get the data into localStorage using this format but StorageObject[thisItemsListID] always gets into the if statement and generates a duplicate item in localStorage and I'm not sure how to access this with a variable. I'm trying to append the new ID if it doesn't exist so if {1:{} exists but current ID is 2 I need to push the new value.
I'm close here and maybe I need to reevaluate the format I'm storing the data string but I'm going in circles here and could use a point in the right direction.
Well, the duplicate item is happening in StorageObject.push(itemProperties).
Try this to update the object:
//StorageObject.push(itemProperties); <-- remove
StorageObject[thisItemsListID] = itemProperties;
[EDIT]
If you want to keep [{"1":{"property1":false,"property2":false}},{"2":{"property1":false,"property2":false}}]. To conditional would be a bit different.
var haveItem = StorageObject.filter(function(item){
return Objects.keys(item)[0] == thisItemsListID;
}).length > 0;
if ( !haveItem ) {
var itemProperties = {};
itemProperties[thisItemsListID] = {};
itemProperties[thisItemsListID]["property1"] = false;
itemProperties[thisItemsListID]["property2"] = false;
StorageObject.push(itemProperties);
localStorage.setItem('session', JSON.stringify(StorageObject));
}
Are you trying to update the object or just overwrite it? Filipes response illustrates how to update the entire storage object by just reassigning the object with the new value.
If you wanted to update just as section/ value of the object you could do so using a for loop. This would allow you to scan the array locate the one property and then remove it, updated it, overwrite it etc.
Here is an example of the loop. Bear in mind This is a snippet from a report library I was building. It uses angular $scope but it is a complex type doing a similar action to your update (here I am setting a label as a favorite/bookmark)
function OnFavoriteComplete(response) {
var id = response.config.data.reportId; //dynamic values set by client
var isFavorite = response.config.data.isFavorite;//dynamic values set by client
var arrayCount = $scope.reportList.length;
//loop my current collection and look for the property id of the label
//then check to see if true or false/this was a toggle enable disable
if (isFavorite) {
for (var i = 0, iLen = arrayCount; i < iLen; i++) {
if ($scope.reportList[i].reportId == id) {
$scope.reportList[i].isFavorite = false;
}
}
}
//if false update the property with the new value
else {
for (var i = 0, iLen = arrayCount; i < iLen; i++) {
if ($scope.reportList[i].reportId == id) {
$scope.reportList[i].isFavorite = true;
}
}
}
};
If you are using another framework like lowDash it has some really nice helper functions for updating and evaluating arrays.

Categories