I have a select field with the list of countries. And I want to show something ONLY for the US selection, and something else for !US selections. But I also want it to do something else when NOTHING is selected. The problem is, Nothing is also inclusive in a non-US selection.
P.S. I know my code is a bit verbose, if you want to offer a smaller solution, I'll be grateful. But I'm ok with it just working
Here's the code
var selectedCountry, selectAutograph
$('.country, .autograph').on('change', function() {
selectedCountry = $('.country').find('option:selected').val();
selectAutograph = $('.autograph').is(":checked")
if (selectedCountry === "United States" && !selectAutograph) {
console.log("Show US Only");
$(".us").show();
$(".int, .intauto, .usauto").hide();
} else if (selectedCountry !== "United States" && !selectAutograph) {
console.log("Show Int Only");
$(".int").show();
$(".us, .intauto, .usauto").hide();
} else if (selectedCountry === "United States" && selectAutograph) {
console.log("Show US and Autograph");
$(".usauto").show();
$(".intauto, .us, .int").hide();
} else if (selectedCountry !== "United States" && selectAutograph) {
console.log("Show Int and Autograph");
$(".intauto").show();
$(".usauto, .us, .int").hide();
} else {
console.log("Show Nothing");
$(".intauto, .usauto, .us, .int").hide();
}
});
.hide {
display: none;
}
<form id="order-form" method="post" role="form">
<select name="country" id="country">
<option value="Select Country">Select Country</option>
<option value="United States">United States</option>
<option value="Canada">Canada</option>
<option value="United Kingdom">United Kingdom</option>
<!-- ... -->
<option value="Zimbabwe">Zimbabwe</option>
</select>
<div >
<input type="checkbox" value="" id="autograph" name="autograph">
<label > Add autograph </label>
</div>
</form>
<div>
<div >
US shipping
</div>
<div >
International shipping
</div>
<div >
US shipping add autograph
</div>
<div >
International shipping add autograph
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Here's a JSFiddle as well. Thanks in advanced
CodePudding user response:
The else
will never run because the Select Country
country option will run in the selectedCountry !== "United States" && !selectAutograph
or selectedCountry !== "United States" && selectAutograph
condition, Also you can simplify the code, by adding data
atttibutes.
Please check this.
var selectedCountry, selectAutograph
var country = {
"Select Country": "non",
"United States": "us",
}
$('.country, .autograph').on('change', function() {
selectedCountry = $('.country').find('option:selected').val();
selectAutograph = $('.autograph').is(":checked")
$('[data-autograpgh], [data-country="non-us"], [data-country="us"]').hide()
if(country[selectedCountry] === "us" && !selectAutograph) {
$('[data-country="us"]:not([data-autograpgh])').show()
} else if(!country[selectedCountry] && !selectAutograph) {
$('[data-country="non-us"]:not([data-autograpgh])').show()
} else if(country[selectedCountry] === "us" && selectAutograph) {
$('[data-country="us"][data-autograpgh]').show()
} else if(!country[selectedCountry] && selectAutograph) {
$('[data-country="non-us"][data-autograpgh]').show()
}
});
.hide {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form id="order-form" method="post" role="form">
<select name="country" id="country" required="">
<option value="Select Country">Select Country</option>
<option value="United States">United States</option>
<option value="Canada">Canada</option>
<option value="United Kingdom">United Kingdom</option>
<option value="Zimbabwe">Zimbabwe</option>
</select>
<div >
<input type="checkbox" value="" id="autograph" name="autograph">
<label > Add autograph </label>
</div>
</form>
<div>
<div data-country="us">
US shipping
</div>
<div data-country="non-us">
International shipping
</div>
<div data-country="us" data-autograpgh>
US shipping add autograph
</div>
<div data-country="non-us" data-autograpgh>
International shipping add autograph
</div>
</div>
CodePudding user response:
While you've already accepted an answer, I wanted to offer an alternative approach:
// creating an Object in which we can access properties
// of individual countries; the key of each object is
// the value from the <select> element:
const countries = {
us: {
country: 'United States',
international: false,
},
canada: {
country: 'Canada',
international: true,
},
uk: {
country: 'United Kingdom',
international: true,
},
zimbabwe: {
country: 'Zimbabwe',
international: true,
}
};
// caching the elements:
let countrySelect = $('.country'),
autograph = $('.autograph');
// binding the anonymous function of the on() method as the event-handler
// for the 'change' event:
$('.country, .autograph').on('change', function() {
// hiding the children of the '.details' element:
$('.details > *').hide();
// retrieving the selected <option> element:
let selectedOption = countrySelect.find(':selected');
// HTMLOptionElement.defaultSelected is a Boolean property which is
// true if the <option> had the selected attribute on page-load, or
// false if the <option> did not have the 'selected' attribute on
// page-load:
if (selectedOption.prop('defaultSelected')) {
// all elements are now hidden by default in the function,
// so no action taken except for logging a statement to the
// console:
console.log("No country selected.");
} else {
// here we retrieve the value of the selected <option>:
let value = selectedOption.val(),
// using destructuring to declare the variables that
// are also property-names from the countries[value]
// property-value:
{
country,
international
} = countries[value],
// determining whether the checkbox is checked, the
// .is() method returns a Boolean reflecting that
// the collection matches the supplied selector:
withAutograph = autograph.is(':checked'),
// here we create the CSS selector, using a template-literal String;
// the first conditional operator tests whether the 'international'
// variable is true; if yes this returns the string 'int', otherwise
// returning the string 'us'
// the second conditional tests to see if 'withAutograph' is true,
// if so returning the string 'auto', othewise an empty string:
selector = `.${international ? 'int' : 'us'}${withAutograph ? 'auto' : ''}`;
// we then use that selector, and call the show() method:
$(selector).show();
}
});
.hide {
display: none;
}
<form id="order-form" method="post" role="form" action="#">
<select name="country" id="country">
<option value="Select Country" selected>Select Country</option>
<!--
Here I've changed the value to a lower-case single string, in
order to reduce the chance of a mis-typed white-space character
causing trouble elsewhere, and use an abbreviation where
possible/obvious to do so:
-->
<option value="us">United States</option>
<option value="canada">Canada</option>
<option value="uk">United Kingdom</option>
<option value="zimbabwe">Zimbabwe</option>
</select>
<div >
<input type="checkbox" value="" id="autograph" name="autograph">
<label > Add autograph </label>
</div>
</form>
<!--
This element was given a class-name ('details') in order to easily hide
the contents without having to refer to them individually:
-->
<div >
<div >
US shipping
</div>
<div >
International shipping
</div>
<div >
US shipping add autograph
</div>
<div >
International shipping add autograph
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
This is, of course, perfectly possible with plain JavaScript:
// caching a reference to the document, along with some utility
// helper functions to simplify life (and reduce typing):
const D = document,
// here we define an alias for querySelector(), which will use
// either document.querySelector() or element.querySelector()
// depending on whether a context is passed to the function;
// if no context is passed document.querySelector() will be
// used, otherwise with a context that Element will be used:
get = (sel, context = D) => context.querySelector(sel),
// as above, but here we call querySelectorAll() and return
// the retrieved NodeList as an Array of Nodes in order to
// utilise Array methods:
getAll = (sel, context = D) => [...context.querySelectorAll(sel)],
// creating an Object in which we can access properties
// of individual countries; the key of each object is
// the value from the <select> element:
countries = {
us: {
country: 'United States',
international: false,
},
canada: {
country: 'Canada',
international: true,
},
uk: {
country: 'United Kingdom',
international: true,
},
zimbabwe: {
country: 'Zimbabwe',
international: true,
}
};
// caching the elements:
let countrySelect = get('.country'),
autograph = get('.autograph'),
// the change-handling function:
changeHandler = (evt) => {
// hiding the children of the '.details' element:
getAll('.details > *').forEach(
(el) => el.classList.add('hide')
);
// retrieving the selected <option> element, with CSS
// the selected <option> matches the :checked pseudo-
// class, and we're looking within the context of the
// countrySelect <select> element:
let selectedOption = get(':checked', countrySelect);
// HTMLOptionElement.defaultSelected is a Boolean property which is
// true if the <option> had the selected attribute on page-load, or
// false if the <option> did not have the 'selected' attribute on
// page-load:
if (selectedOption.defaultSelected) {
// all elements are now hidden by default in the function,
// so no action taken except for logging a statement to the
// console:
console.log("No country selected.");
} else {
// here we retrieve the value of the selected <option>:
let value = selectedOption.value,
// using destructuring to declare the variables that
// are also property-names from the countries[value]
// property-value:
{
country,
international
} = countries[value],
// determining whether the checkbox is checked, the
// property itself returns a Boolean indicating whether
// the node is checked (true) or unchecked (false):
withAutograph = autograph.checked,
// here we create the CSS selector, using a template-literal String;
// the first conditional operator tests whether the 'international'
// variable is true; if yes this returns the string 'int', otherwise
// returning the string 'us'
// the second conditional tests to see if 'withAutograph' is true,
// if so returning the string 'auto', othewise an empty string:
selector = `.${international ? 'int' : 'us'}${withAutograph ? 'auto' : ''}`;
// here we retreive all elements matching the selector, and then use
// Array.prototype.forEach() to iterate over that Array of Nodes with
// an Arrow function:
getAll(selector).forEach(
// here we pass in a reference to the current Node of the Array,
// and we remove the 'hide' class-name from the Element's classList:
(el) => el.classList.remove('hide')
);
}
};
// using Array.prototype.forEach() to iterate over the Array-literal which
// contains both interactive elements with which the user interacts:
[countrySelect, autograph].forEach(
// binding the changeHandler function as the event-handler for the 'change' event:
(el) => el.addEventListener('change', changeHandler)
);
.hide {
display: none;
}
<form id="order-form" method="post" role="form" action="#">
<select name="country" id="country">
<option value="Select Country" selected>Select Country</option>
<!--
Here I've changed the value to a lower-case single string, in
order to reduce the chance of a mis-typed white-space character
causing trouble elsewhere, and use an abbreviation where
possible/obvious to do so:
-->
<option value="us">United States</option>
<option value="canada">Canada</option>
<option value="uk">United Kingdom</option>
<option value="zimbabwe">Zimbabwe</option>
</select>
<div >
<input type="checkbox" value="" id="autograph" name="autograph">
<label > Add autograph </label>
</div>
</form>
<!--
This element was given a class-name ('details') in order to easily hide
the contents without having to refer to them individually:
-->
<div >
<div >
US shipping
</div>
<div >
International shipping
</div>
<div >
US shipping add autograph
</div>
<div >
International shipping add autograph
</div>
</div>
References:
- JavaScript:
- jQuery: