While you've already accepted an answer I'd suggest, if using plain – non-library – JavaScript is preferred, the following:
// named function to handle the changes:
function toggleParentStyle(opts) {
// the default settings:
var settings = {
// activeClass: String, the class-name by
// which the 'active'/'on' state is denoted:
'activeClass': 'active',
// targetElementSelector: String,
// the CSS selector to identify the elements
// whose style is to be altered:
'targetElementSelector': 'li',
// uniquelyActive: Boolean, determines
// whether only one element can have the
// 'active' state/'activeClass' class-name:
'uniquelyActive' : true
},
// caching the 'this' Node:
trigger = this;
// iterating over the (possibly) passed-in opts
// Object that can be used to override the
// default settings:
for (var prop in opts) {
// if the opts Object has prop as an
// own-property (one not inherited from
// the Object's prototype):
if (opts.hasOwnProperty(prop)) {
// we update the relevant property of
// the settings Object to be equal to
// that of the opts Object:
settings[prop] = opts[prop];
}
}
// caching the targetElementSelector and activeClass
// with shorter names (for convenience):
var selector = settings.targetElementSelector,
c = settings.activeClass,
// caching the closest ancestor of the element
// triggering the function that matches the
// selector:
ancestor = trigger.closest(selector),
// finding the currently-active element (if any),
// moving from the found ancestor element:
selectedSibling = ancestor
// to its parentNode:
.parentNode
// finding the first/only element in that
// parent element that matches the selector
// and has the class-name:
.querySelector(selector + '.' + c);
// if settings.uniquelyActive is true, and
// there is a selected-sibling:
if (settings.uniquelyActive && selectedSibling) {
// we remove the class-name:
selectedSibling.classList.remove( c );
}
// here we access the ancestor element's classList,
// and if the ancestor.classList.contains the class-name
// (Boolean true) we use the 'remove' method, if it does not
// contain the class-name (Boolean false) we use the 'add'
// method, and pass the class-name as an argument:
ancestor.classList[ancestor.classList.contains( c ) ? 'remove' : 'add'](c);
// Note: for radio inputs this isn't necessary, as a radio
// can't be changed by clicking it, but this might be a
// necessary check were check-box inputs to be used instead.
}
// finding all the radio-inputs in the document:
var radios = document.querySelectorAll('input[type=radio]'),
// converting the HTMLCollection into an Array, using
// Array.prototype.slice and Function.prototype.call():
radiosArray = Array.prototype.slice.call(radios, 0);
// iterating over the radiosArray using Array.prototype.forEach():
radiosArray.forEach(function(radio) {
// binding the toggleParentStyle to handle the change
// event of the radio inputs:
radio.addEventListener('change', toggleParentStyle);
});
function toggleParentStyle(opts) {
var settings = {
'activeClass': 'active',
'targetElementSelector': 'li',
'uniquelyActive': true
},
trigger = this;
for (var prop in opts) {
if (opts.hasOwnProperty(prop)) {
settings[prop] = opts[prop];
}
}
var selector = settings.targetElementSelector,
ancestor = trigger.closest(selector),
c = settings.activeClass,
selectedSibling = ancestor
.parentNode
.querySelector(selector + '.' + c);
if (settings.uniquelyActive && selectedSibling) {
selectedSibling.classList.remove(c);
}
ancestor.classList[ancestor.classList.contains(c) ? 'remove' : 'add'](c);
}
var radios = document.querySelectorAll('input[type=radio]'),
radiosArray = Array.prototype.slice.call(radios, 0);
radiosArray.forEach(function(radio) {
radio.addEventListener('change', toggleParentStyle);
});
.job-manager-term-checklist {
margin: 1em 0 0;
padding: 0;
list-style: none;
overflow: hidden;
}
.job-manager-term-checklist li {
border: 1px solid #ccc;
overflow: auto;
padding: 5px;
margin-left: 5px;
border-radius: 5px;
background-color: #ebf1f9;
width: 20%;
}
.job-manager-term-checklist li:hover {
background-color: #4e83ca;
color: #fff;
}
li.active {
background-color: limegreen;
}
<div class="field required-field">
<ul class="job-manager-term-checklist job-manager-term-checklist-job_category">
<li id="job_listing_category-72" class="popular-category">
<label class="selectit">
<input value="72" type="radio" name="tax_input[job_listing_category][]" id="in-job_listing_category-72">1</label>
</li>
<li id="job_listing_category-73">
<label class="selectit">
<input value="73" type="radio" name="tax_input[job_listing_category][]" id="in-job_listing_category-73">2</label>
</li>
<li id="job_listing_category-75">
<label class="selectit">
<input value="75" type="radio" name="tax_input[job_listing_category][]" id="in-job_listing_category-75">3</label>
</li>
<li id="job_listing_category-76">
<label class="selectit">
<input value="76" type="radio" name="tax_input[job_listing_category][]" id="in-job_listing_category-76">4</label>
</li>
<li id="job_listing_category-80">
<label class="selectit">
<input value="80" type="radio" name="tax_input[job_listing_category][]" id="in-job_listing_category-80">5</label>
</li>
<li id="job_listing_category-86">
<label class="selectit">
<input value="86" type="radio" name="tax_input[job_listing_category][]" id="in-job_listing_category-86">6</label>
</li>
<li id="job_listing_category-98">
<label class="selectit">
<input value="98" type="radio" name="tax_input[job_listing_category][]" id="in-job_listing_category-98">7</label>
</li>
</ul>
</div>
JS Fiddle demo
To show the above using radio <input>
elements, but passing in different settings:
radiosArray.forEach(function(radio) {
radio.addEventListener('change', function () {
// using Function.prototype.call()
// to set the function's 'this' (the radio input),
// and passing an Object as the second argument to
// contain the Opts Object:
toggleParentStyle.call(this, {
// allowing multiple elements to be styled as active:
'uniquelyActive' : false,
// passing in a different class-name:
'activeClass' : 'anAlternativeClassName'
});
});
});
function toggleParentStyle(opts) {
var settings = {
'activeClass': 'active',
'targetElementSelector': 'li',
'uniquelyActive': true
},
trigger = this;
for (var prop in opts) {
if (opts.hasOwnProperty(prop)) {
settings[prop] = opts[prop];
}
}
var selector = settings.targetElementSelector,
ancestor = trigger.closest(selector),
c = settings.activeClass,
selectedSibling = ancestor
.parentNode
.querySelector(selector + '.' + c);
if (settings.uniquelyActive && selectedSibling) {
selectedSibling.classList.remove(c);
}
ancestor.classList[ancestor.classList.contains(c) ? 'remove' : 'add'](c);
}
var radios = document.querySelectorAll('input[type=radio]'),
radiosArray = Array.prototype.slice.call(radios, 0);
radiosArray.forEach(function(radio) {
radio.addEventListener('change', function () {
toggleParentStyle.call(this, {
'uniquelyActive' : false,
'activeClass' : 'anAlternativeClassName'
});
});
});
.job-manager-term-checklist {
margin: 1em 0 0;
padding: 0;
list-style: none;
overflow: hidden;
}
.job-manager-term-checklist li {
border: 1px solid #ccc;
overflow: auto;
padding: 5px;
margin-left: 5px;
border-radius: 5px;
background-color: #ebf1f9;
width: 20%;
}
.job-manager-term-checklist li:hover {
background-color: #4e83ca;
color: #fff;
}
li.active {
background-color: limegreen;
}
li.anAlternativeClassName {
background-color: #f90;
}
<div class="field required-field">
<ul class="job-manager-term-checklist job-manager-term-checklist-job_category">
<li id="job_listing_category-72" class="popular-category">
<label class="selectit">
<input value="72" type="radio" name="tax_input[job_listing_category][]" id="in-job_listing_category-72">1</label>
</li>
<li id="job_listing_category-73">
<label class="selectit">
<input value="73" type="radio" name="tax_input[job_listing_category][]" id="in-job_listing_category-73">2</label>
</li>
<li id="job_listing_category-75">
<label class="selectit">
<input value="75" type="radio" name="tax_input[job_listing_category][]" id="in-job_listing_category-75">3</label>
</li>
<li id="job_listing_category-76">
<label class="selectit">
<input value="76" type="radio" name="tax_input[job_listing_category][]" id="in-job_listing_category-76">4</label>
</li>
<li id="job_listing_category-80">
<label class="selectit">
<input value="80" type="radio" name="tax_input[job_listing_category][]" id="in-job_listing_category-80">5</label>
</li>
<li id="job_listing_category-86">
<label class="selectit">
<input value="86" type="radio" name="tax_input[job_listing_category][]" id="in-job_listing_category-86">6</label>
</li>
<li id="job_listing_category-98">
<label class="selectit">
<input value="98" type="radio" name="tax_input[job_listing_category][]" id="in-job_listing_category-98">7</label>
</li>
</ul>
</div>
JS Fiddle demo.
And showing how it might be used for check-boxes:
// selecting inputs of type=checkbox:
var checkboxes = document.querySelectorAll('input[type=checkbox]'),
// convert checkboxes HTMLCollection to an Array:
checkboxArray = Array.prototype.slice.call(checkboxes, 0);
// exactly as above, but passing in different elements:
checkboxArray.forEach(function(check) {
check.addEventListener('change', function () {
toggleParentStyle.call(this, {
// ensuring multiple checkbox ancestors can be
// selected:
'uniquelyActive' : false,
'activeClass' : 'anAlternativeClassName'
});
});
});
function toggleParentStyle(opts) {
var settings = {
'activeClass': 'active',
'targetElementSelector': 'li',
'uniquelyActive': true
},
trigger = this;
for (var prop in opts) {
if (opts.hasOwnProperty(prop)) {
settings[prop] = opts[prop];
}
}
var selector = settings.targetElementSelector,
ancestor = trigger.closest(selector),
c = settings.activeClass,
selectedSibling = ancestor
.parentNode
.querySelector(selector + '.' + c);
if (settings.uniquelyActive && selectedSibling) {
selectedSibling.classList.remove(c);
}
ancestor.classList[ancestor.classList.contains(c) ? 'remove' : 'add'](c);
}
var checkboxes = document.querySelectorAll('input[type=checkbox]'),
checkboxArray = Array.prototype.slice.call(checkboxes, 0);
checkboxArray.forEach(function(check) {
check.addEventListener('change', function() {
toggleParentStyle.call(this, {
'uniquelyActive': false,
'activeClass': 'anAlternativeClassName'
});
});
});
.job-manager-term-checklist {
margin: 1em 0 0;
padding: 0;
list-style: none;
overflow: hidden;
}
.job-manager-term-checklist li {
border: 1px solid #ccc;
overflow: auto;
padding: 5px;
margin-left: 5px;
border-radius: 5px;
background-color: #ebf1f9;
width: 20%;
}
.job-manager-term-checklist li:hover {
background-color: #4e83ca;
color: #fff;
}
li.active {
background-color: limegreen;
}
li.anAlternativeClassName {
background-color: #f90;
}
<div class="field required-field">
<ul class="job-manager-term-checklist job-manager-term-checklist-job_category">
<li id="job_listing_category-72" class="popular-category">
<label class="selectit">
<input value="72" type="checkbox" name="tax_input[job_listing_category][]" id="in-job_listing_category-72">1</label>
</li>
<li id="job_listing_category-73">
<label class="selectit">
<input value="73" type="checkbox" name="tax_input[job_listing_category][]" id="in-job_listing_category-73">2</label>
</li>
<li id="job_listing_category-75">
<label class="selectit">
<input value="75" type="checkbox" name="tax_input[job_listing_category][]" id="in-job_listing_category-75">3</label>
</li>
<li id="job_listing_category-76">
<label class="selectit">
<input value="76" type="checkbox" name="tax_input[job_listing_category][]" id="in-job_listing_category-76">4</label>
</li>
<li id="job_listing_category-80">
<label class="selectit">
<input value="80" type="checkbox" name="tax_input[job_listing_category][]" id="in-job_listing_category-80">5</label>
</li>
<li id="job_listing_category-86">
<label class="selectit">
<input value="86" type="checkbox" name="tax_input[job_listing_category][]" id="in-job_listing_category-86">6</label>
</li>
<li id="job_listing_category-98">
<label class="selectit">
<input value="98" type="checkbox" name="tax_input[job_listing_category][]" id="in-job_listing_category-98">7</label>
</li>
</ul>
</div>
JS Fiddle demo.
References: