variables seem to be coupled - javascript

I've got this weird problem with my JavaScript code.
I'm trying to create dynamically loading select boxes without the luxury of something like React.
It compares values of other select boxes so that a value can only be selected in once. So if a value is already set in one select box, it cannot be selected again.
For this I use a list of original values, clone those values into a new variable and remove the ones already selected and then create new lists.
Works fine albeit the numerous loops. The only problem is that if I remove an item from the cloned variable, the original also changes.
Even if I push the original variable in a prototype object or use const.
window.initial_abstract_list = ["Option one", "Option two", "Option three", "Option four", "Option five"];
// Set the option values
function reset_abstract_list() {
var in_list = [];
var new_list = window.initial_abstract_list;
console.log(window.initial_abstract_list); /// window.initial_abstract_list changes!!!
// Get selected value of all select boxes
$.each($('select.values-list'), function(index, value) {
in_list.push($(value).val().toString())
});
// Remove already set values from list
$.each($('select.values-list'), function(index, value) {
$.each(in_list, function(index2, value2) {
delete new_list[value2.toString()];
});
});
// Generate new options for select boxes
$.each($('select.values-list'), function(index, value) {
var current_selected_key = $(value).val().toString();
var current_selected_val = $('option:selected', value).text();
$(value).empty();
$(value).append($('<option></option>')
.attr('value', current_selected_key)
.text(current_selected_val));
for (var index2 in new_list) {
"use strict";
$(value).append($('<option></option>')
.attr('value', index2)
.text(new_list[index2]));
};
});
}
// Alter content on change select boxes
jQuery(document).ready(function($) {
$(document).on('click', 'button', function(e) {
reset_abstract_list();
})
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select class="values-list">
<option value="0">Option one</option>
<option value="1">Option two</option>
<option value="2">Option three</option>
<option value="3">Option four</option>
</select>
<select class="values-list">
<option value="0">Option one</option>
<option value="1">Option two</option>
<option value="2">Option three</option>
<option value="3">Option four</option>
</select>
<select class="values-list">
<option value="0">Option one</option>
<option value="1">Option two</option>
<option value="2">Option three</option>
<option value="3">Option four</option>
</select>
<button>Ye olde button</button>

When you set your new_list to the default list, it's basically creating a reference to the original. You need to instead copy the values of the original list so they aren't coupled.
var new_list = window.initial_abstract_list.slice();

By doing var new_list = window.initial_abstract_list; you are only creating a reference to the original array. Any changes made to new_list will reflect in the initial array.
What you want to do is create a deep copy of the initial array, so as to get a different variable but with the same values. You can do this like so:
var new_list = jQuery.extend(true, {}, window.initial_abstract_list);

Related

Multiple select get Selected options in order selected

i have a multiple select like the following
<select name="cars" id="cars" multiple>
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
<option value="opel">Opel</option>
<option value="audi">Audi</option>
</select>
that i have implemented chosen plugin on i have an onchange listener that adds selected elements to an array like so
$("#cars").change(function () {
var selected = [];
for (var option of document.getElementById('cars').options) {
if (option.selected) {
selected.push(option.value);
}
}
console.log(selected);
});
however in which ever option i select the items they always end up arranging themselves in the order they are in the multiple select
for example by selecting the values Volvo , Audi, Saab in that order results in the following array
Array [ "Volvo" ]
Array [ "Volvo", "Audi" ]
Array(3) [ "Volvo", "Saab", "Audi" ]
Is there a way that i can add elements in a multiple select to an array in the order which they were selected?
You always get the same order of the selected array because you create it each time you run your onChange function. So the solution would be to make it a global variable. When you do that, your array won't be empty at the second choice tho, so you have to take care of removing items from it.
Here's some code
var selected = [];
$("#cars").change(function () {
for (var option of document.getElementById('cars').options) {
var value = option.value;
if (option.selected) {
if(selected.indexOf(value) < 0){//we only add element if it's not present in the array
selected.push(value);
}
}else{
if(selected.indexOf(value) >= 0){ //we only remove item if it is present
selected.splice(selected.indexOf(value),1)
}
}
}
console.log(selected);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<select name="cars" id="cars" multiple>
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
<option value="opel">Opel</option>
<option value="audi">Audi</option>
</select>

Issue with get selected option and return

I have an issue with the return value in js. I need to return it because I wanna use it in
var rusiavimas = selectedServices();
So, my function looks like this.
function selectedServices()
{
var selectedServices = [];
$('.common_change').change(function(){
selectedServices = $(this).val();
alert(selectedServices);
});
return selectedServices;
}
My HTML code
<select name="rusiavimas" class="common_change" id="cars">
<option value="none" selected disabled hidden>
Pasirinkite variantą
</option>
<option value="naujausi">Naujausi viršuje</option>
<option value="pigiausi" >Pigiausi viršuje</option>
<option value="brangiausi">Brangiausi viršuje</option>
</select>
Then I select the option, in the alert function I get the correct value, but in my return, it's not returning it.
Your code contains a lot of problem, I try to fix them below
Your JS script is always return an empty array, because when you call the function var rusiavimas = selectedServices(); the inner .change function is not runs and not change the value of the array
var selectedServices = [];
$('.common_change').change(function(){
selectedServices.push($(this).val());
if(selectedServices.length > 0){
alert("selected service: " + selectedServices.toString());
}
console.log(selectedServices);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<select name="rusiavimas" class="common_change" id="cars">
<option value="none" selected disabled hidden>
Pasirinkite variantą
</option>
<option value="naujausi">Naujausi viršuje</option>
<option value="pigiausi" >Pigiausi viršuje</option>
<option value="brangiausi">Brangiausi viršuje</option>
</select>
Each time after changing your array it gives to your array the last common value.
The best way as was said an comments use selectedSerices.push($(this).val());
You can also use deep copy, which is less recommended in your case selectedSerices = [...selectedSerices, $(this).val()]. I guess it will help you!

If value in select option is lower than in second select option, then change option

I want to achieve:
If I select "16" in first select box and bigger value in second, for example "17", then in second select automatically changing to "16".
Just if value in first select box is lower than second, always change to same values, for example 16 to 16, 18 to 18.
<select id="from_age_js" name="from_age" class="select-advertise-style">
<option value="f13">13</option>
<option value="f14">14</option>
<option value="f15">15</option>
<option value="f16">16</option>
<option value="f17">17</option>
<option value="f18" selected>18</option>
<option value="f19">19</option>
<option value="f20">20</option>
</select>
—
<select id="to_age_js" name="to_age" class="select-advertise-style">
<option value="t13">13</option>
<option value="t14">14</option>
<option value="t15">15</option>
<option value="t16">16</option>
<option value="t17">17</option>
<option value="t18">18</option>
<option value="t20" selected>20+</option>
</select>
That's an easy one, in your case, with pure javascript, I would do something like this:
function checkit()
{
//Store the two dropdowns for easy reference
var fromAge = document.getElementById('from_age_js');
var toAge = document.getElementById('to_age_js');
//Verify if the toAge value is minor, to see if the conditional code will be executed
if( fromAge.options[fromAge.selectedIndex].value >
toAge.options[toAge.selectedIndex].value)
{
//In that case, match the values to be the same...
document.getElementById('to_age_js').value =
fromAge.options[fromAge.selectedIndex].value;
}
}
And you just have to add that function to where you want it to be called. I would choose to add the onchange event from Javascript within the select dropdowns. Like this:
<select id="from_age_js" name="from_age" class="select-advertise-style" onchange="checkit();">
You can see a working example here:
https://jsfiddle.net/8cmad3tz/19/

accessing global variables after setting them javascript

I am trying to keep track of changes to a select box in django. My code below is working up to alert(change.new_time);, so I am making the object correctly-
var changed_select_box_array = [];
function handleChanges(id){
var x = document.getElementById(id).selectedIndex;
var time = document.getElementsByTagName("option")[x].value;
var change = {id:id, new_time:time};
alert(change.id);
alert(change.new_time);
changed_select_box_array[changed_select_box_array.length] = change;
alert(changed_select_box_array[0].id);
}
but I cannot access the new item in the array. I tried 4-5 different ways and followed some rules for global variables in funcs I found on this site, and I cannot access anything from the new array. Am I doing something wrong adding to the array? I tried push too. Thank you
You can use Object as associative array.
var changed_select_box_array = {};
function handleChanges() {
var x = this.selectedIndex;
var id = this.id;
var time = this.getElementsByTagName("option")[x].value;
var change = { id: id, new_time: time };
changed_select_box_array[id] = change;
console.log(changed_select_box_array);
}
<!--Emitation of some select inputs with change events-->
<select id="s1" onchange="handleChanges.call(this)">
<option value="val1">Value 1</option>
<option value="val2">Value 2</option>
<option value="val3">Value 3</option>
</select>
<select id="s2" onchange="handleChanges.call(this)">
<option value="val4">Value 1</option>
<option value="val5">Value 2</option>
<option value="val6">Value 3</option>
</select>

Fill second dropdown with the same value as the first dropdown

I have a dynamic number of dropdowns. When a value is selected in the first dropdown, the value of the second and so on dropdowns will be the same with the first dropdown. But the user has the option to change the value of the second and so on dropdowns, but not changing the first and other dropdown's value.
<select name="dropdown[]">
<option value="1">Sony</option>
<option value="2">Nintendo</option>
<option value="3">Microsoft</option>
</select>
<select name="dropdown[]">
<option value="1">Sony</option>
<option value="2">Nintendo</option>
<option value="3">Microsoft</option>
</select>
<select name="dropdown[]">
<option value="1">Sony</option>
<option value="2">Nintendo</option>
<option value="3">Microsoft</option>
</select>
How can I achieve this using javascript or jquery libraries?
You can attach a listener to the first select element:
var selects = document.querySelectorAll('select[name="dropdown[]"]');
selects[0].addEventListener('change', function () {
for (var i = 0; i < selects.length; i++) {
selects[i].value = selects[0].value;
}
});
When the value of only the first select changes, it updates the values of the other selects. This way does not rely on any 3rd-party libraries.
Demo: http://jsfiddle.net/cuefb9ag/
Use a change event and then alter the other dropdowns:
$("select[name=dropdown\\[\\]]").change(function() {
var value = this.value;
$("select[name=dropdown\\[\\]]").not(this).val(value);
});
Demo: http://jsfiddle.net/awv14f6r/1/
If you want to change them in order (first alters the second, etc) - use next along with this
$(this).next("select").val(value);
var id = $('#DropDownID1 option:selected').val();
var textValue = $('#DropDownID1 option:selected').text();
$('#DropDownID2').prop('selectedIndex', 0);
$('#DropDownID2').select2('data', {
val: id,
text: textValue
});
$('#DropDownID2 option:selected').val(id);
}

Categories