I'm building a search form but have something strange going on with the selected="selected" option not being highlighted.
The form's pulling data from a database and duplicates are then being removed using javascript (seen below). The website is built using ExpressionEngine and the form is using Solspace Super Search.
The strange thing is that for option's that only display one result such as 'Andover', the dropdown selects 'Andover' but if more than one result is found (such as Bournemouth) then the dropdown reverts to the first option (All locations) rather than Bournemouth, even though the Bournemouth option features selected="selected".
Here's a sample of the code that's being output, any ideas what's going on here?
<select name="club_feed_town" id="locationList">
<option value="">All Locations</option>
<option value="Andover">Andover</option>
<option value="Bishops waltham">Bishops Waltham</option>
<option value="Blandford forum">Blandford Forum</option>
<option value="Boscombe">Boscombe</option>
<option selected="selected" value="Bournemouth">Bournemouth</option>
</select>
Here's the script that's removing duplicates if that helps:
$(document).ready(function() {
var optionValues = [];
var lastRemoved = null;
$('#locationList option').each(function(){
if($.inArray(this.value, optionValues) >-1){
$(this).remove();
// remember the very last removed one
lastRemoved = $(this);
}else{
optionValues.push(this.value);
}
});
// after removing duplicates, add the very last removed one back to the list
$('#locationList').append(lastRemoved);
});
As always, any thoughts or suggestions are welcome.
Thanks in advance,
Tom
I just made some add in your js code to make it work. Just give it a look.
$(document).ready(function() {
var optionValues = [];
var lastRemoved = null;
$('#locationList option').each(function(i){
if($.inArray(this.value, optionValues) >-1){
//////////////////////add in code///////////////////////////////
if($(this).prop('selected')){
$(this).removeAttr("selected");
}
$('#locationList').prop('selectedIndex',i-1);
//////////////////////end of my code//////////////////////////////
// remember the very last removed one
$(this).remove();
lastRemoved = $(this);
}else{
optionValues.push(this.value);
}
});
// after removing duplicates, add the very last removed one back to the list
$('#locationList').append(lastRemoved);
});
Related
I am in the process of building an e-Commerce shop and have hit a small bump in the road for my actual product page. Based on any product options set that would add to the price if selected, I would like to be able to update the price on the page live when these options have been added. I have managed to iterate through every element with a "data-price-effect" attribute attached to them, HOWEVER, when it comes to a select element, I would need to check if the item is selected as an option, each option has their respective price change attribute of course, but the value would only update to the actual select element.
Here is my code upto now:
function updatePrice(){
$('[data-price-effect]').each(function( index ) {
// do something
});
}
Basic HTML set-up to explain further:
<form>
<input type="text" name="foo" onchange="updatePrice();" data-price-effect="10.00" />
<select name="bar" onchange="updatePrice();">
<option selected value="Item1" data-price-effect="5.00">Item 1</option>
<option selected value="Item2" data-price-effect="8.00">Item 2</option>
<option selected value="Item3" data-price-effect="10.00">Item 3</option>
</select>
</form>
I have NO idea how to even logically do this, not even with some huge messy code. Any pointers here from someone more experienced with Javascript?
Instead of having "updatePrice()" on each element, you could have a listener for all form elements for the function:
var EffectElements = $('form input[data-price-effect], form select');
EffectElements.on('change', function() {
var PriceEffect = 0;
EffectElements.each(function() { // Loop through elements
if ($(this).is('select')) { //if this element is a select
$(this).children().each(function() { //Loop through the child elements (options)
if ($(this).is(':selected')) { //if this option is selected
PriceEffect += parseFloat($(this).attr('data-price-effect'));
}
});
} else {
PriceEffect += parseFloat($(this).attr('data-price-effect'));
}
});
});
You could then use the PriceEffect variable to update your price on the website.
Ultimately it's the IS function doing the dirty work you needed ~_o
Working Example
I have an issue with the data which is sent from a drop down menu, the selector only returns a single value, even when multiple values are selected. I have searched online for a solution to this, but they all use PHP, JQuery or some method outside the scope of the course I am taking; to capture multiple selected items. I have tried .value of the individual options, but that returns all of the options rather than just the ones which are selected. Is there some kind of trick to sending multiple values?
Here is my code for the menu. For example If I select JAVA PROGRAMMING, NETWORKS and VIDEO GAMES, only JAVA PROGRAMMING is sent.
<select multiple id="CK_Expertise">
<option id="CK_Exp1" value="Java programming">JAVA PROGRAMMING</option>
<option id="CK_Exp2" value="Networks">NETWORKS</option>
<option id="CK_Exp3" value="Video game programming">VIDEO GAMES</option>
<option id="CK_Exp4" value="Accounter">ACCOUNTER</option>
<option id="CK_Exp5" value="Help Desk">HELPDESK</option>
<option id="CK_Exp6" value="C++ programming">C++</option>
<option id="CK_Exp7" value="Programming">PROGRAMMING</option>
</select>
I have also tried using the Select Object in the DOM, http://www.w3schools.com/jsref/dom_obj_select.asp
which has a few methods for accessing the options in the dropdown menu. One method in particular called selectedIndex, seemed to be what I am looking for, however it only returns the the index of the first selected option, instead of all of the selected options.
Is there a simple solution to this using just Javascript and the DOM?
Thanks
- Chris
Get the options, iterate and check if they are selected, and add the values to an array
var select = document.getElementById('CK_Expertise'),
options = select.getElementsByTagName('option'),
values = [];
for (var i=options.length; i--;) {
if (options[i].selected) values.push(options[i].value)
}
console.log(values)
FIDDLE
or being a little more fancy
var select = document.getElementById('CK_Expertise'),
values = Array.prototype.filter.call(select.options, function(el) {
return el.selected;
}).map(function(el) {
return el.value;
});
console.log(values)
FIDDLE
You could use the select.selectedOptions property:
select.onchange = function() {
var values = [].map.call(this.selectedOptions, function(opt){
return opt.value;
});
};
document.getElementById('CK_Expertise').onchange = function() {
document.querySelector('pre').textContent = JSON.stringify([].map.call(
this.selectedOptions, function(opt){ return opt.value; }
));
}
<select multiple id="CK_Expertise">
<option id="CK_Exp1" value="Java programming">JAVA PROGRAMMING</option>
<option id="CK_Exp2" value="Networks">NETWORKS</option>
<option id="CK_Exp3" value="Video game programming">VIDEO GAMES</option>
<option id="CK_Exp4" value="Accounter">ACCOUNTER</option>
<option id="CK_Exp5" value="Help Desk">HELPDESK</option>
<option id="CK_Exp6" value="C++ programming">C++</option>
<option id="CK_Exp7" value="Programming">PROGRAMMING</option>
</select>
<pre></pre>
If you can use jQuery, this will give you all the values
$(document).ready(function(){
$('#CK_Expertise').change(function(e){
var values = $('#CK_Expertise').val()
alert(values);
});
});
HTH,
-Ted
You could iterate storing select.selectedIndex in an array and unselecting the corresponding option to get the next one:
select.onchange = function() {
var i, indices=[], values = [];
while((i=this.selectedIndex) > -1) {
indices.push(i);
values.push(this.value);
this.options[i].selected = false;
}
while((i=indices.pop()) > -1)
this.options[i].selected = true;
console.log(values);
}
Demo
This way you avoid iterating over all options, but you must iterate twice over the selected ones (first to unselect them, them to select them again).
Why not using an indexed variable in the SELECT command?
<SELECT MULTIPLE id="stuff" name="stuff[]">
<OPTION value=1>First stuff</option>
<OPTION value=2>Second stuff</option>
<OPTION value=3>Third stuff</option>
</SELECT>
In that case it's easy to read the array:
$out=$_REQUEST['stuff'];
foreach($out AS $thing) {
echo '<br />'.$thing;
}
Sorry for the poor indentation, but I just wanted to show the way I use for solving this case!
var select = document.getElementById('CK_Expertise'),
options = select.selectedOptions,
values = [];
for(let i=0;i<options.length;i++)
{
values.push(options[i].value);
}
console.log(values);
I have a drop down box in which allows for a "category" to be selected, if it is changed it loads the new category as shown in the code below. I have since introduced a "Sub-Category" system and am in need of modifying this code slightly. I found the following information to be very helpful:
How to attach different events on multiple selectors through .on function in jquery?.
However, it doesn't quite solve my problem... I could use that to run two separate events for each selector within the same function but I need to run both simultaneously in the event both a "category" and "sub-category" are selected. Though they need to also be capable of running separate, in the event only one is selected. I'm fairly new to js/jquery so the more info you can provide the better! Thank you very much!
<script type='text/javascript'>
$(document).ready(function()
{
$('select#selectCategory').change(function()
{
var cat = $('select#selectCategory').val();
var subcat
if(cat > 0)
{
var param = '&category_id=' + cat;
}else{
var param = '';
}
var href = './videoroom.php?action=video_gallery'+ param +'&page=1';
window.location.href = href;
});
});
</script>
Here is the HTML section related to the already written jquery code:
<select style="min-weight:100px;" name="filter_by_cat" id="selectCategory">
<option value="0">All</option>
<option value="9">Wizard101</option>
<option value="10">Pirate101</option>
<option value="11">Pet Derby</option>
<option value="14">Misc/Fun</option>
</select>
And here is the new bit I added for the newly created Sub-Category:
<select style="min-weight:100px;" name="filter_by_subcat" id="selectSubCategory">
<option value="0">All</option>
<option value="21">General PvP</option>
<option value="22">PvPC Matches</option>
<option value="23">PvP Guides</option>
<option value="24">Miscellaneous</option>
</select>
Add the event listener to both dropdowns and check both of them when either is changed:
jsFiddle
$('#selectCategory, #selectSubCategory').change(function() {
var cat = $('#selectCategory').val();
var subcat = $('#selectSubCategory').val();
var params = [
'action=video_gallery',
'page=1'
];
if (cat > 0) {
params.push('category_id='+ cat);
if (subcat > 0) {
params.push('subcategory_id='+ subcat);
}
}
var href = './videoroom.php?'+ params.join('&');
window.location.href = href;
});
I'm assuming you only want the subcategory choice to be taken into account when the main category is selected. If that's not the case, move the second if-statement outside the first one.
I also refactored your code a little to make it more easily extensible and (IMO) cleaner. I'm adding all the params to an array and them just joining them at the end. If you need to add any more params, just put them in the array as well.
We have two dropdowns that according to your selection it changes part of the string in some div containers. The purpose of this is to return URLs to give to clients.
This is a sample of the code
<select name="lstLanguage" id="lstLanguage">
<OPTION VALUE="">-- Generic default ---</OPTION>
<OPTION ID="Arabic" VALUE="AR">Arabic</OPTION>
<OPTION ID="German" VALUE="D">German</OPTION>
</select>
<select name="lstTemplate" id="lstTemplate">
<OPTION VALUE="">-- Generic default ---</OPTION>
<OPTION VALUE="1">Member</OPTION>
<OPTION VALUE="2">NonMember</OPTION>
</select>
<div id='Ind_URL'>http://example.com/Registration.asp?Language_Code=?Role=</div>
<div id='Ind_W_URL'>http://example.com/Registration.asp?Language_Code=?Role=</div>
<div id='Login_URL'>http://example.com/?Language_Code=</div>
And this is the jQuery we currently have, which was provided by irama.
$(function(){
divIDs = [
'Ind_URL',
'Ind_W_URL',
'Login_URL',
];
$('#lstTemplate').bind('change', function(){
role = $(this).find('option:selected').val();
updateURLDivs(langCode=null, role);
});
$('#lstLanguage').bind('change', function(){
langCode = $(this).find('option:selected').val();
updateURLDivs(langCode, role=null);
});
updateURLDivs = function (langCode, role) {
for (i in divIDs) {
currentDiv = $('#'+divIDs[i]);
if (langCode !== null) {
currentDiv.data('Language_Code', langCode);
}
if (role !== null) {
currentDiv.data('role', role);
}
// Cache original div contents, so that the select menu can be changed more than once.
if (typeof currentDiv.data('contents') == 'undefined') {
divContents = currentDiv .html();
currentDiv .data('contents', divContents);
} else {
divContents = currentDiv .data('contents');
}
currentDiv.empty().append(
divContents
.replace('role=','role='+currentDiv.data('role'))
.replace('Language_Code=','Language_Code='+currentDiv.data('Language_Code'))
);
}
}
});
This is working fine, but this morning we found a few issues
It is currently updating both parameters, no matter if you change one or both. We need it to update if you change the template, just the template and if you change the language just the language.
If nothing is selected we need it to replace it with a blank not with undefined as it is currently doing
If we change the Template it also needs to replace Registration.asp to PersonImport.asp from the URLs
This is how it should work
The div containers need to have the default URLs in them
If I change the language (lstLanguage) it should just change the Language_Code on the DIV containers. Then if I select the language option with no value ("Generic default") the Language_Code should be blank ''
If I change the template (lstTemplate) it should change the Role on the DIV containers. Also should change Registration.asp to PersonImport.asp. Then if I select the template option with no value ("Generic Default) the Role should be blank '' and PersonImport.asp should go back to Registration.asp.
I'm not a good coder on this, but it would be great if any of you can give me a hand with this.
Thanks in advance
Federico
I have create a fiddle with a lot of improvement in your code. Take a look.
Working demo
This is a little more complicated than the title makes it out to be, but here are the essential business rules:
There are three select menus on the
page, each filled with the same
options and values.
There will always be three select
menus.
There will always be the same number
of options/values in each select
menu.
Selecting a question in any of the
menus will remove that question as an option from
the other two menus.
Re-selecting a different question
from any of the menus will bring
back the question that was
previously removed from the other
two menus at the index it was at previously.
I've tried this a few different ways, and the thing that is killing me is number 5. I know that it wouldn't be inserted at the exact index because some questions may have already been removed, which would reorder the index. It basically needs an insertBefore or insertAfter that puts it in the same "slot".
Even if you don't post any code, some thoughts on how you might approach this would be extremely helpful. The select menus and jQuery look something like this, but I've had numerous tries at it in different variations:
jQuery:
$(function() {
$(".questions").change(function() {
var t = this;
var s = $(t).find(":selected");
// Remove, but no "insert previously selected" yet...
$(".questions").each(function(i) {
if (t != this) {
$(this).find("option[value=" + s.val() + "]").remove();
}
});
});
});
HTML:
<select name="select1" class="questions">
<option value="1">Please select an option...</option>
<option value="2">What is your favorite color?</option>
<option value="3">What is your pet's name?</option>
<option value="4">How old are you?</option>
</select>
<select name="select2" class="questions">
<option value="1">Please select an option...</option>
<option value="2">What is your favorite color?</option>
<option value="3">What is your pet's name?</option>
<option value="4">How old are you?</option>
</select>
<select name="select3" class="questions">
<option value="1">Please select an option...</option>
<option value="2">What is your favorite color?</option>
<option value="3">What is your pet's name?</option>
<option value="4">How old are you?</option>
</select>
Don't remove the elements, hide them. With removing, you are causing you a lot more problems than necessary. This works for me:
$(function() {
$('select.questions').change(function() {
var hidden = [];
// Get the values that should be hidden
$('select.questions').each(function() {
var val = $(this).find('option:selected').val();
if(val > 0) {
hidden.push($(this).find('option:selected').val());
}
});
// Show all options...
$('select.questions option').show().removeAttr('disabled');
// ...and hide those that should be invisible
for(var i in hidden) {
// Note the not(':selected'); we don't want to hide the option from where
// it's active. The hidden option should also be disabled to prevent it
// from submitting accidentally (just in case).
$('select.questions option[value='+hidden[i]+']')
.not(':selected')
.hide()
.attr('disabled', 'disabled');
}
});
});
I made a small change to your HTML also, I denoted an option that should always be visible with a value of 0. So the valid options go from 1 to 3.
Here's a working example, tell me if I misunderstood you:
http://www.ulmanen.fi/stuff/selecthide.php
I was working on a solution of this recently and modified this code to remove rather than disable/hide. For my solution it was required (I'm also using UI to style the select elements). Here's how I did it:
// Copy an existing select element
var cloned = $('select[name="select1"]').clone();
// Each time someone changes a select
$('select.questions').live('change',function() {
// Get the current values, then reset the selects to their original state
var hidden[];
$('select.questions').each(function() {
hidden.push($(this).val());
$(this).html(cloned.html());
});
// Look through the selects
for (var i in hidden) {
$('select.questions').each(function() {
// If this is not the current select
if ((parseInt(i)) != $(this).parent().index()) {
// Remove the ones that were selected elsewhere
$(this).find('option[value="'+hidden[i]+'"]').not('option[value="0"]').remove();
} else {
// Otherwise, just select the right one
$(this).find('option[value="'+hidden[i]+'"]').not('option[value="0"]').attr('selected','selected');
}
});
}
});