Reputation: 151
So I've got an input field that I'm trying to populate using two separate drop-down menus. I've got it working with a single drop-down currently, but I'm unable to do two. Here's an example of what I'm trying to accomplish:
<select type="text" id="make">
<option value="">- select one -</option>
<option value="chevy">Chevy</option>
</select>
<select type="text" id="model">
<option value="">- select one -</option>
<option value="silverado">Silverado</option>
</select>
<input type="text" id="input" value="" />
So the value of the text input should be 'Chevy Silverado' if both fields are selected. Here's the script that I've got so far:
$(function(){
$('select#make').bind('change', function(){
$('input#input').val($(this).val());
});
});
Which works great for one drop down, but obviously does nothing for the other. Any ideas? I've tried a few solutions that I'd found with absolutely no success. Thanks for looking!
$(function(){
var $makemodel = $('.makemodel');
$('.makemodel').on('change',function(){
$('#input').val($makemodel.eq(0).val()+' '+$makemodel.eq(1).val());
});
});
Upvotes: 1
Views: 2026
Reputation: 253318
I'd suggest amending the HTML somewhat, to group the select
elements within a single parent, and binding, using on()
, the change
event to that element:
<form action="#" method="post">
<fieldset>
<select type="text" id="make">
<option value="">- select one -</option>
<option value="chevy">Chevy</option>
</select>
<select type="text" id="model">
<option value="">- select one -</option>
<option value="silverado">Silverado</option>
</select>
<input type="text" id="input" value="" />
</fieldset>
</form>
With the jQuery:
$('fieldset').on('change', function(){
var self = $(this);
$('#input').val(function(){
return self.find('select').map(function(){ return this.value; }).get().join(' ');
});
});
Modifying further, to use a class
to identify the summary element (the text-input into which the value will be inserted) reduces the reliance on known elements, and allows for more general-purpose code:
$('fieldset').on('change', function(){
var self = $(this);
self.find('.summary').val(function(){
return self.find('select').map(function(){ return this.value; }).get().join(' ');
});
});
And a non-jQuery, plain-JavaScript approach to the same solution (albeit only works in those browsers that support document.querySelector()
/document.querySelectorAll()
and addEventListener()
):
function summarise(container, what, sumClass) {
var els = container.querySelectorAll(what),
sumTo = container.querySelector(sumClass),
vals = [];
for (var i = 0, len = els.length; i < len; i++) {
vals.push(els[i].value);
}
sumTo.value = vals.join(' ').trim();
}
var fieldsets = document.querySelectorAll('fieldset');
for (var i = 0, len = fieldsets.length; i < len; i++) {
fieldsets[i].addEventListener('change', function(){
summarise(this, 'select', '.summary');
}, false);
}
Upvotes: 2
Reputation: 16359
No problem! Please forgive the length of this answer, it offers multiple options depending on whether you place greater importance on code readability vs efficiency. It will only make marginal differences in speed but hopefully it shall inspire you to think of speed in your overall code!
Easy solution:
$('#make,#model').on('change',function(){
$('#input').val($('#make').val()+' '+$('#model').val());
});
More efficient:
Give your select
s a class:
<select type="text" id="make" class="MakeModel">
<option value="">- select one -</option>
<option value="chevy">Chevy</option>
</select>
<select type="text" id="model" class="MakeModel">
<option value="">- select one -</option>
<option value="silverado">Silverado</option>
</select>
<input type="text" id="input" value="" />
And then select on the class:
$('.MakeModel').on('change',function(){
$('#input').val($('#make').val()+' '+$('#model').val());
});
Giving it a class just makes it slightly easier for the parser to query only one selector rather than two.
Most efficient:
Use the appropriate .eq()
values and caching instead of querying the ID selectors again:
var $makemodel = $('.MakeModel');
$makemodel.on('change',function(){
$('#input').val($makemodel.eq(0).val()+' '+$makemodel.eq(1).val());
});
This means the select items do not need to be requeried since all the objects of .MakeModel
are contained within the function under the cached $makemodel
and you can just specify the object order number to reference a specific one.
jsFiddle to show what I mean here
Additional notes:
Notice the use of .on
rather than .bind
, which is the more correct syntax for modern jQuery applications.
Also, using tagnames before ID or class will actually make your selectors less efficient, as the parser needs to verify the ID/class is associated with the tag, rather than just grabbing the ID (which should be unique anyway) or class name (which should be appropriately isolated in its naming).
Upvotes: 4
Reputation: 6726
Simple solution:
$(function() {
$('#make, #model').on('change', function() {
var makeCurr = $('#make').find(":selected");
var madelCurr = $('#model').find(":selected");
var make = (makeCurr.val() != '') ? makeCurr.text() : '';
var model = (madelCurr.val() != '') ? madelCurr.text() : '';
$('input#input').val(make + ' ' + model);
});
});
Upvotes: 2