jQuery change element on select - global script for multiple select inputs - javascript

I am creating a form builder script. I have a select input where the user can select the form element they want to use, depending on their selection ("select", "checkbox" or "radio") another form field is displayed allowing users to input their options.
Users can create as many instances of form elements as they want, so each select input has a dynamically created id that corresponds to the id of the hidden form field. I then use jQuery to determine whether the "options" field should be hidden or not (triggered on change of the form elements select input).
Currently, for every instance, I have the following code addedabove the select input:
<script>
jQuery(document).ready(function($) {
var arr = ['select', 'checkbox', 'radio'];
var thisForm = 'select.input-type-118';
function showHideSelect() {
var val = $(thisForm + ' option:selected').val();
var selectOptions = $('#select-options-118')
if (arr.indexOf(val) >= 0) {
selectOptions.show();
} else {
selectOptions.hide();
}
}
showHideSelect();
$(thisForm).change(function() {
showHideSelect();
});
});
</script>
Where var thisForm and var selectOptions are added dynamically and refer to the select option below this script.
I'm wondering if there is a better way to do this rather than repeat several instances of this, at the moment, a users page cold look like this:
<script>
...
</script>
<select>
...
</select>
<textarea>
This is hidden depending on the select option
</textarea>
<script>
...
</script>
<select>
...
</select>
<textarea>
This is hidden depending on the select option
</textarea>
<script>
...
</script>
<select>
...
</select>
<textarea>
This is hidden depending on the select option
</textarea>
...etc...etc
My concern is that I don't think it's best practice to have so many instances of the same script, but I'm unsure how to write a global script that will allow me to show/hide the textarea on an individual basis.
I have shown a more accurate depiction of my workings on this jsfiddle here:
https://jsfiddle.net/46stb05y/4/

You can use Event Delegation Concepts. https://learn.jquery.com/events/event-delegation/
With this you can change your code to
$(document).on('change','select',function() { //common to all your select items
showHideSelect($(this)); // passing the select element which trigerred the change event
});
This will work even on the select items that are added dynamically
You must change your function to receive the element as the parameter.
function showHideSelect($selectElement) {
var val = $selectElement.val();
var selectOptionsId = $selectElement.attr('class').replace('input-type','select-options');
var selectOptions = $("#"+selectOptionsId);
if (arr.indexOf(val) >= 0) {
selectOptions.show();
} else {
selectOptions.hide();
}
}
Here is the Working JsFiddle

Related

Passing checkbox to hidden input

So i have a checkbox which is loading from php on other page and since i cannot get the values of them ive written a jquery script that was supposed to check if a checkbox was checked and if so it would mark the corresponding hidden input with value 1 or 0.
But seems like it's only working for 1 in the loop no matter what i do.
<script>
$(document).ready(function() {
var total = <?php echo $count; ?>;
for (i = 0; i < total; i++) {
$('input[type="checkbox"]').change(function(event) {
if($(this).is(":checked")){
$(".check_"+i).val(1);
console.log("added"+i);
}else{
$(".check_"+i).val(0);
console.log("removed"+i);
}
});
}
});
</script>
looks like you are registering change event handler of checkbox for multiple times instead you need to put 1 or 0 on multiple i=hidden inputs.
You don't need loop here, just add change event handler for all checkboxes having id starts with check_ and read same id to create input hidden class selector. Set the value to input hidden.
See below code -
<script>
$(document).ready(function() {
//bind change event for checkbox having id starts with "check_"
$(document).on('change','input[type="checkbox"][id^=check_]', function(event) {
var id = $(this).attr('id');// id of checkbox checked/unchecked
$("."+id).val($(this).is(':checked')?1:0); // put 1 or 0 to the matching hidden input
});
});
</script>

Checking g-select mapping properties

Hello I created this dropdownbox
<g:select from="${[['key':1, 'value':'text1'],['key':2, 'value':'text2' else']]}" optionKey="key" optionValue="value" name="mine"/>
My question is how can I print the message "hi" everytime I have clicked on the text1 field
For the select you can use attribute onchange to set the function it will call when value is changed:
<g:select onchange="printmsg(this)" from="${[['key':1, 'value':'text1']....
Then you write that function that checks the new value for the select and determines if it is what you are looking for.
printmsg = function(element) {
var chosen = $(element).val();
if (chosen === "text1"){
alert("Omg. What have you done?!");
}
}
Of course put Javascript in gsp page (and for this code add jquery library) as well.

How to "dropdown" a select when click on somewhere else?

This is the thing I have:
A normal select with a few options...
And the thing is, I do need to click in some other div and when I click on that one, I want the select list to show up as they were clicked normally and then allow the user to choose from the select options
I have some code already
<div onclick="set_select()"></div>
<select class='form-control' id='opts'>
<option selected disabled></option>
<option>Contacto</option>
<option>Entrevista</option>
<option>Prensa</option>
<option>Conferencias</option>
</select>
<script type="text/javascript">
function set_select(){
var select = document.getElementById('opts');
return select.active = true;
}
</script>
Not possible with plain html/javascript.
You need some plugin to replace your standard select field with divs and then use your function to trigger that divs. One is selectmenu: https://jqueryui.com/selectmenu/#product-selection
There is a lot more of them available: https://www.google.pl/search?q=js+select+replacement&gws_rd=cr&ei=wN5ZV8SjMIGLsgGP_IboDQ
This is "sort" of possible but not trivial and you will need to possibly do some management of the effect as I do here in the "change" event for the select. Not perfect but perhaps this can give you a start.
Note you MIGHT just want to use the "focus" on the select or, set the visible size as I do here, set the select size on the change to 0 with event.target.size = 0; and so forth.
Revised the markup a bit to allow the click handler:
<div id="clicker">clicker</div>
<select class='form-control' id='opts'>
<option selected disabled></option>
<option>Contacto</option>
<option>Entrevista</option>
<option>Prensa</option>
<option>Conferencias</option>
</select>
Here is the script, as I said, not perfect but you can decide how you handle the change/click events.
window.onload = function() {
var id = "clicker";
var div = document.getElementById(id);
var select = document.getElementById("opts");
div.onclick = function(event) {
console.log('clicker div');
select.size = select.options.length;
select.focus();
};
select.onclick = function(event) {
console.log('opt clicked');
};
select.onchange = function(event) {
console.log('opt change');
var index = event.target.selectedIndex;
console.log(index);
event.target.size = index + 2;
};
}
Here is a fiddle you can use to get you started: https://jsfiddle.net/MarkSchultheiss/mL0b7ubr/
Note that if you wish to use the "default" size for the select you can detect that like so:
if (event.target.type == "select-one") {
event.target.size = 1;
} else {
event.target.size = 4;
}
Here is a fiddle with that change and a bit cleaner on the event attachment: https://jsfiddle.net/MarkSchultheiss/mL0b7ubr/1/

how to find all the select elements that have changed?

let's say I have a form that contains several "select" element that the User can choose.
when ready to submit, I need to find all the "select" that have changed.
how can I do it?
for example:
<form>
<input type="text" name="a"/>
<select name="b">...</select>
<select name="c">...</select>
<select name="d">...</select>
</form>
Using jQuery, something like this should work:
$('select').change(function() {
$(this).addClass('changed');
});
$('form').submit(function() {
var changed_selects = $('select.changed');
// do what you want with the changed selects
});
I would take advantage of the defaultSelected property on HTMLOptionElement instead of trying to keep track of selects that have changed:
form.onsubmit = function() {
var selects = form.getElementsByTagName("select")
, i
, changedSelects = []
, selected
, select;
/* Iterate over all selects in the form: */
for (i = 0; i < selects.length; i++) {
select = selects[i];
/* Get the currently selected <option> element: */
selected = select[select.selectedIndex];
/* Determine if the currently selected option is the one selected by default: */
if (!selected.defaultSelected) {
changedSelects.push(select);
}
}
alert(changedSelects.length);
}
You can iterate over all of the select elements on your form, determine if the selected option is the one that was selected by default, and push each one whose selected option wasn't the default into an array.
Example: http://jsfiddle.net/andrewwhitaker/abFr3/
You could register an event listener (using onchange, etc.) to determine if any changes were made.
Alternatively, you could keep a private copy of all of the previous values, then run a comparison before submit to check for changes.
Do something like:
var selectedVal = $("select[name='a'] option:selected").val();
//check this with your default selected val
You can attach the onchange event listener to each <select> element. When the event is triggered, you can store the actual elements in an a temporary array and reference it later when you are ready to submit. Note that the array can hold the actual DOM elements.
You need to clarify what you mean by "the select have changed".
If you mean have changed from their default value, then you should have one option on each select (usually the first) set as the default selected option. Then you can iterate over the selects and see if the option with the selected attribute (or where the defaultSelected property is true) is the selected option, e.g.
<script>
function anyChanged(){
var select, selects = document.getElementsByTagName('select');
for (var i=0, iLen=selects.length; i<iLen; i++) {
select = selects[i];
if (!select.options[select.selectedIndex].defaultSelected) {
// the selected option isn't the default
alert('select ' + (select.id || select.name) + ' changed');
}
}
}
</script>
<select name="one">
<option selected>one
<option>two
<option>three
</select>
<button onclick="anyChanged()">Check</button>
However, if you want to see if the user has changed the selected option based on some other logic, you need to say what it is.

Using JavaScript and JQuery, How Can I Maintain the Selected State of a Dynamically-Updated HTML Select Element?

I have a form UI whereby several sections require duplicate HTML select list to be updated dynamically from a single, dynamically-updatable select list.
The dynamically-updatable list works just fine, in that new options can be added and removed on-the-fly. I can then get this update to propagate through each of the duplicate lists using JQuery .find(). I have even added a bit of logic to maintain the currently selected index of the original select list.
What I'm not able to do is maintain the selected state of each of the duplicate select lists as new options are added and removed from the original select list. As each update to the original select list iterates through each duplicate select list, they lose their currently selected option index.
Here is an example of my conundrum--*EDIT--I would encourage you to try and execute the code I've provided below and apply your theories before suggesting a solution, as none of the suggestions so far have worked. I believe you will find this problem a good deal trickier than you might assume at first:
<form>
<div id="duplicates">
<!--// I need for each of these duplicates to maintain their currently selected option index as the original updates dynamically //-->
<select>
</select>
<select>
</select>
<select>
</select>
</div>
<div>
<input type="button" value="add/copy" onclick="var original_select = document.getElementById('original'); var new_option = document.createElement('option'); new_option.text = 'Option #' + original_select.length; new_option.value = new_option.text; document.getElementById('original').add(new_option); original_select.options[original_select.options.length-1].selected = 'selected'; updateDuplicates();" />
<input type="button" value="remove" onclick="var original_select = document.getElementById('original'); var current_selected = original_select.selectedIndex; original_select.remove(original_select[current_selected]); if(original_select.options.length){original_select.options[current_selected < original_select.options.length?current_selected:current_selected - 1].selected = 'selected';} updateDuplicates();" />
<select id="original">
</select>
</div>
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
<script type="text/javascript">
function updateDuplicates(){
$("#duplicates").find("select").html($("#original").html());
}
</script>
</form>
It is important to note that the duplicate HTML select lists should remain somewhat arbitrary, if at all possible (i.e.; no ID's) as this method needs to apply generically to other dynamically-created select lists throughout the document.
Thanks in advance!
Still not 100% sure what you're asking but it seems like this should do what you're looking for and is a few less lines of code.
(function () {
function updateDuplicates() {
$("#duplicates").find("select").html($("#original").html());
$('#duplicates select').each(function () {
var lastSelectedValue = $(this).data('lastSelectedValue');
$(this).val(lastSelectedValue || $(this).val());
});
}
$(document).ready(function () {
$('button:contains(remove)').bind('click', function (e) {
e.preventDefault();
var original_select = document.getElementById('original'),
current_selected = original_select.selectedIndex;
original_select.remove(original_select[current_selected]);
if (original_select.options.length) {
original_select.options[current_selected < original_select.options.length ? current_selected : current_selected - 1].selected = 'selected';
}
updateDuplicates();
});
$('button:contains(add/copy)').bind('click', function (e) {
e.preventDefault();
var original_select = document.getElementById('original'),
new_option = document.createElement('option');
new_option.text = 'Option #' + original_select.length;
new_option.value = new_option.text;
document.getElementById('original').add(new_option);
original_select.options[original_select.options.length - 1].selected = 'selected';
updateDuplicates();
});
$('#duplicates select').bind('change', function () {
$(this).data('lastSelectedValue', $(this).val());
});
} ());
} ());
EDIT: I changed your markup to be
<button>add/copy</button>
<button>remove</button>
just set the currently selected item/value of select to some variable, then do your operation,
finally reselect the value to the select.
Okay, I think I have a workable approach to a solution, if not a clumsy one. The tricky part isn't adding a value to the original list, because the added option is always at the end of the list. The problem comes in removing a select option because doing so changes the index of the currently selectedIndex. I've tested using Google Chrome on a Mac with no errors. I have commented the code to demonstrate how I approached my solution:
<form>
<div id="duplicates">
<!--// Each of these select lists should maintain their currently selected index //-->
<select>
</select>
<select>
</select>
<select>
</select>
</div>
<div>
<!--// Using a generic function to capture each event //-->
<input type="button" value="add/copy" onClick="updateDuplicates('add');" />
<input type="button" value="remove" onClick="updateDuplicates('remove');" />
<select id="original">
</select>
</div>
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
<script type="text/javascript">
function updateDuplicates(editMode){
///* Capture the selectedIndex of each select list and store that value in an Array *///
var original_select = document.getElementById('original');
var current_selected = new Array();
$("#duplicates").find("select").each(function(index, element) {
current_selected[index] = element.selectedIndex;
});
switch(editMode){
case "add":
var new_option = document.createElement('option');
new_option.text = 'Option #' + original_select.length;
new_option.value = new_option.text;
original_select.add(new_option);
original_select.options[original_select.options.length-1].selected = 'selected';
///* Traverse each select element and copy the original into it, then set the defaultSelected attribute for each *///
$("#duplicates").find("select").each(function(index, element){
$(element).html($("#original").html());
///* Retrieve the currently selected state stored in the array from before, making sure it is a non -1 value, then set the defaultSelected attribute of the currently indexed element... *///
if(current_selected[index] > -1){
element.options[current_selected[index]].defaultSelected = true;
}
});
break;
case "remove":
var current_index = original_select.selectedIndex;
original_select.remove(original_select[current_index]);
///* Thou shalt not remove from thine empty list *///
if(original_select.options.length){
original_select.options[current_index > 0?current_index - 1:0].selected = 'selected';
}
///* Traverse each select element and copy the original into it... *///
$("#duplicates").find("select").each(function(index, element){
$(element).html($("#original").html());
///* Avoid operating on empty lists... *///
if(original_select.options.length){
///* Retrieve the currently selected state stored in the array from before, making sure it is a non -1 value... *///
if(current_selected[index] > -1){
///* If the stored index state is less or equal to the currently selected index of the original... *///
if(current_selected[index] <= current_index){
element.options[current_selected[index]].defaultSelected = true;
///* ...otherwise, the stored index state must be greater than the currently selected index of the original, and therefore we want to select the index after the stored state *///
}else{
element.options[current_selected[index] - 1].defaultSelected = true;
}
}
}
});
}
}
</script>
</form>
There is plenty of room to modify my code so that options can be inserted after the currently selectedIndex rather than appended to the end of the original select list. Theoretically, a multi-select list/menu should work as well. Have at thee.
I'm sure one of the geniuses here will be able to do this same thing with cleaner, prettier code than mine. Thanks to everyone who reviewed and commented on my original question! Cheers.
If you can reset a little, I think that the problem is you are setting your select list's HTML to another list's HTML. The browser probably doesn't try to preserve the currently selected item if all the of underlying html is being changed.
So, I think what you might try doing is explicitly adding the option elements to the target lists.
Try this jsfiddle. If you select an item other than the default first item and click "add", notice that the selected item is maintained. So you need to be a little more surgical in your managing of the target list items.
Maybe that'll help or maybe I missed the point.

Categories