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

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?

Related

Dynamically setting options for a select elements skips first element

I've dynamically built an options array divided in two options group. These options groups are stored in a javascript array named ogs. The code for the same is as below:
var ogs = [];
for (optGroup in optionsList) {
var og = document.createElement('optgroup');
og.label = optGroup;
var ops = optionsList[optGroup];
for (op in ops) {
var o = document.createElement('option');
o.value = op;
o.text = ops[op];
og.appendChild(o);
}
ogs.push(og);
}
Now, I'm trying to add these options to 2 select elements, as below:
var from_el = document.getElementById('from_selector'), to_el = document.getElementById('to_selector');
for (i = 0; i < ogs.length; ++i) {
var og = ogs[i];
from_el.add(og);
to_el.add(og);
}
However, at the end of the script, only to_selector has the options populated, whereas from_selector remains empty. The reason I'm populating the options like this is because both these select elements use select2, and any other method (such as innerHTML) is taking significantly longer. I've also tried putting these selectors in array and iterating over them, always the last select gets populated, whereas first select remains empty.
Figured out the issue. The problem was in the following lines:
from_el.add(og);
to_el.add(og);
When og was getting added to to_el, it was getting detached from from_el. The solution was to replace this with.
from_el.add(og);
to_el.add(og.cloneNode(true));

An array resets when I submit the second value

When I add a value to the array and console.log it the first value gets removed and the array restarts always leaving the array with one value. How can I add multiple values by clicking the same button each time?
function calcBudget(){
//expenseCostValue is an input in a form.
const expenseValue = expenseCostValue.value;
const itemList = [];
itemList.push(expenseValue);
console.log(itemList);
You're probably redefining your array every time. Put the const itemList = [] outside of the click event handler. and just run itemList.push(expenseValue) inside the click event handler.
You must change the scope of your Array
function calcBudget() {
const expenseValue = expenseCostValue.value;
const itemList = []; // → remove the array
console.log(itemList);
}
const itemList = []; // we declare it out of our function
function calcBudget() {
const expenseValue = expenseCostValue.value;
itemList.push(expenseValue);
console.log(itemList);
}
I hope I have been helpful

How to call/edit all html elements with class names that are found inside an array?

I have managed to create the array with the names that I need. These names are pushed or removed from the array based on user’s clicks on various html elements(buttons).
I am attempting to use the values collected within the array to call changes upon html elements that have class names corresponding/matching the names within the array.
I have managed to create a function that activates a window alert that allows me to see and verify that I am able to cycle through all elements collected within the array. But I got stuck. I couldn’t figure out how to use the individual values/names within the array to call the specific classes of html elements.
I have tried:
for (var a = 0; a < array.length; a++) {
document.getElelemntsByClassName(“.”+array[a]).classList.add(“new”);
//and//
document.querySelectorAll(“.”+array[a]).classList.add(“new”);
//none of them worked. So I wasn’t able to get through to the specific html elements.//
window.alert(“.”+array[a]);
//This responds properly. I can get multiple alerts, one at the time, with all the names I am expecting to see.//
}
Thank you in advance for your help.
I believe you want to use an object instead of an array, since indexes on an array will change as you remove items. That said, you may not even need the object, depending on what you want to do with the element. In the snippet below, I added classNames as an object to treat it as an associative array, for example:
// This is shared between two functions
const LIST_ITEM_SELECTOR = '.js-list-item'
// Get top-level elements
const listElement = document.querySelector('.js-list')
const listItemTemplate = document.querySelector('.js-list-item-template')
const addButton = document.querySelector('.js-add-button')
const logButton = document.querySelector('.js-log-button')
// Replaces "array" from your example
const classNames = {}
// Removes the list item from the list element (also delete from classNames)
const handleDelete = e => {
const parentListItem = e.currentTarget.closest(LIST_ITEM_SELECTOR)
const listItemId = parentListItem.dataset.id
delete classNames[listItemId]
parentListItem.remove()
}
// Updates after each "Add"
let nextId = 0
const handleAdd = () => {
// Build new element from the template
const newListItem = listItemTemplate.content
.cloneNode(true)
.querySelector(LIST_ITEM_SELECTOR)
// Add class to the element and the "classNames" object
const className = `id-${nextId}`
newListItem.classList.add(className)
classNames[nextId] = className
// Add data-id
newListItem.dataset.id = nextId
// Update text
newListItem.querySelector('.js-text').textContent = `Item Text ${nextId}`
// Add delete event listener to the nested x button
newListItem.querySelector('.js-x-button').addEventListener('click', handleDelete)
// Append the newListItem to the end of the list
listElement.appendChild(newListItem)
// Prep the nextId for the next "Add" click
nextId += 1
}
addButton.addEventListener('click', handleAdd)
logButton.addEventListener('click', () => {
console.dir(classNames)
})
<button class="js-add-button">Add</button>
<ul class="js-list"></ul>
<template class="js-list-item-template">
<li class="js-list-item">
<span class="js-text">Item Text</span>
<button class="js-x-button">x</button>
</li>
</template>
<button class="js-log-button">Log Out Data</button>

Pre-fill form with local storage

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);
// ...

How to get selected values of Kendo Multi Select?

I'm using Kendo multi select as follow but i can't get selected values
var multiselect = $("#SelectRoles").data("kendoMultiSelect");
var selectedData= [];
var items = multiselect.value();
for (var itm in items)
{
selectedData.push(itm);
}
but array selectedData return indices of items in multiselect not values .
You can also assign the array, returned from the value() method, directly to the variable, e.g.:
var ms = $("#multiselect").kendoMultiSelect({
value: ["1", "2"]
}).data('kendoMultiSelect');
var selectedItems = ms.value();
console.log(selectedItems); // ["1", "2"]
Use this other one returns indices.
var multiselect = $("#SelectRoles").data("kendoMultiSelect");
var selectedData= [];
var items = multiselect.value();
for (var i=0;i<items.length;i++)
{
selectedData.push(items[i]);
}
Your original code doesn't look wrong. Are you sure you are getting only indices? Perhaps you should post your MultiSelect code as well. I found this question because I had the same problem and used the other answers for reference, but I found them overcomplicated. So let me answer in another complicated way :)
Here's what I've got. I know it's more code than you need, but I think it's important to see the full picture here. First let me set this up. There's a problem with the Kendo().MultiSelect.Name("SomeName") property if you are using it more than once. "Name" sets not only the html name, but the id as well, and you never want two ids with the same identifier. So in my code, I am appending a unique Id to my MultiSelect.Name property to ensure a unique id. I am putting the MultiSelect in each row of a table of people. I am showing this to make sure you are using the DataValueField property so you are able to get the selected values (not the text you see in the ui). If you are just showing a list of text values with no id behind them, perhaps that is why you are getting the wrong data?
#foreach (var cm in Model.CaseMembers)
{
<tr>
<td>
#(Html.Kendo().MultiSelect()
.Name("IsDelegateFor" + cm.CaseMemberId)
.Placeholder("is a delegate for..")
.DataTextField("FullName")
.DataValueField("CaseMemberId")
.BindTo(Model.Attorneys)
)
</td>
</tr>
}
then, later on, in my jQuery where I attempt to extract out the DataValueField (CaseMemberId), which is the array of selected values of the MultiSelect...
var sRows = [];
$('#cmGrid tr').each(function () {
// 'this' is a tr
$tr = $(this);
// create an object that will hold my array of selected values (and other stuff)
var rec = {};
rec.IsADelegateFor = [];
// loop over all tds in current row
$('td', $tr).each(function (colIndex, col) {
if (colIndex === 3) {
// make sure our MultiSelect exists in this td
if ($(this).find("#IsDelegateFor" + rec.CaseMemberId).length) {
// it exists, so grab the array of selected ids and assign to our record array
rec.IsADelegateFor = $(this).find("#IsDelegateFor" + rec.CaseMemberId).data("kendoMultiSelect").value();
}
}
}
// add this tr to the collection
sRows.push(rec);
}
so this is all a super verbose way of saying that this single line, as the other people mentioned works perfectly to grab the ids. There is no need to iterate over the .value() array and push the contents to another array!
rec.IsADelegateFor = $(this).find("#IsDelegateFor" + rec.CaseMemberId).data("kendoMultiSelect").value();
So in your original code, there is no reason the following should not work,
var multiselect = $("#SelectRoles").data("kendoMultiSelect");
var selectedData = [];
selectedData = multiselect.value();
console.log(selectedData);
unless
you don't have your MultiSelect set up properly in C# with DataValueField
you have multiple MultiSelects on the page with the exact same id and it's reading from a different one than you think.
You don't even have value fields, just a list of text.
var selected = $("#multi").data("kendoMultiSelect").value();
The solution given by volvox works.
Below is jquery version,
var multiselect = $("#SelectRoles").data("kendoMultiSelect");
var selectedData= [];
var items = multiselect.value();
$.each(items ,function(i,v){
selectedData.push(v);
});

Categories