Reverse changes when value is no longer selected (specified IDs) - javascript

I have a function that changes the color of a text of one of 12 DIVs on my website.
$('.position_select').change(function(){
var selected = $(this).val();
var shelf = $("#mockup_shelf_" + selected)
$(shelf).css({ color: "#FF6633" });
}).change();
It's a mock-up for a user to show on which position they've chosen to display their buttons. It's based on which of the numbers (from 1 to 12) are selected in select tag:
f.select :position, (1..12), {prompt: 'Select Position'}, {required: 'true', class: "position_select" }
I want to change this DIV's text back to black (or all unselected DIVs) if the user unselects this specific position and chooses another. How can I do it?
Colors get back to what they should be on page reload, but that's not the point.

Easiest way is to just update all elements to the default color, and then change the color of the element that corresponds to the selected item like this:
$('.position_select').change(function(){
//reset all elements color
$("[id^=mockup_shelf_]").css({ color: "#000000" });
//now find and set the color of the selected item
var selected = $(this).val();
var shelf = $("#mockup_shelf_" + selected)
$(shelf).css({ color: "#FF6633" });
}).change();
I'm using the starts with attribute selector since the beginning of every ID is the same.
http://www.w3schools.com/cssref/sel_attr_begin.asp
The [attribute^=value] selector matches every element whose attribute
value begins with a specified value.
Alternately, you could assign the same class to all mockup_shelf elements and then use this class selector to target them all: $(".mockup_shelf").css({ color: "#000000" });
And since good things come in threes, you could also completely eliminate any styling information from the script and create 2 css classes in your stylesheet (allowing you to do more complex styling easier). For example:
.mockup_shelf {
color: #000000;
}
.mockup_shelf.selected {
color: #FF6633;
}
All of your mockup_shelf elements would have the mockup_shelf class, and then in script you could add or remove the selected class like so:
$('.position_select').change(function(){
//reset selected element's color
$(".mockup_shelf.selected").removeClass("selected");
//now find and set the color of the selected item
var selected = $(this).val();
var shelf = $("#mockup_shelf_" + selected)
$(shelf).addClass("selected");
}).change();
EDIT
Since you clarified that you have a multi-select box, I've gone ahead and created a sample fiddle showing how to accomplish this with multiple selections:
https://jsfiddle.net/ofhw085r/
$('.position_select').change(function() {
//remove class from all shelves to reset them
$(".mockup_shelf.selected").removeClass("selected");
var $position_select = $(this); //explicitly labeling this to avoid confusion in the next part
$position_select.find("option:selected").each(function() {
var $option = $(this); //'this' now has a new context, so label it to avoid confusing it with 'this' in the outer context
var shelf = $("#mockup_shelf_" + $option.val());
shelf.addClass("selected");
});
}).change();
Essentially, every time the change event fires on your select, you'll reset the styles on all mockup_shelf elements and then loop through every selected option (using jquery's built-in :selected selector), and then add the selected class to the associated shelf.

Related

Select neighbor of element selected by class and attribute

I have almost completed this but am stuck on an advanced selector. I am trying to select a label next to a radio button, but its a little more complex than that.
I have a select box. Only radio buttons (and their sibling labels) in which the value of the select matches the name (well part of) of the radio button.
I have a JS fiddle set up, what I am looking to do, is on selection of January, everything except Jan should be hidden, and when i select February, it should change. I'm trying to do this with just the name and no additional classes but if it comes down to it, I can add them.
http://jsfiddle.net/alpha1beta/G9Sz2/2/
Below is my working selector to get the radio button, and now am looking at how to get their + label next to it
$('.radio([name="insights[interview_questions[' + curr_sel + ']]"])').css('display','inline');
Thanks in advance!
Try
var $radios = $('.radio'), $all = $radios.add($radios.nextUntil('.radio'));
$("#interview_month").change(function () {
var $mon = $radios.filter('.radio[name="insights[interview_questions[' + this.value + ']]"]');
var $cur = $mon.add($mon.nextUntil('.radio')).show();
$all.not($cur).hide()
}).change();
Demo: Fiddle
You may want to check the next() function, it returns the next sibling
Try this:
$("#interview_month").change(function () {
$('.radio , label').hide();
var sel = '.radio[name*="' + $("#interview_month").val() + '"]';
$(sel).add(sel+'+label').css('display', 'inline');
});

Setting a variable using the value of multiple selects, each time any of the selects is changed

I have a list of items that I'm trying to "filter" with a set of 4 selects by matching the value of the select options to the classes I have applied to the list items. Right now, I have it working so that each time you choose a new option with any of the 4 selects, the entire list is reset, and only those items with a class that matches the value of the option you just selected is visible. I would like to have it work so that each time a new option is selected from any of the 4 selects, I could filter by the values of all 4 selects, not just the one that was just changed.
Here's what I have right now - any help is appreciated!
$(".sort-options select").change(function() {
var topics = $(this).val();
$(".list-schools li").hide().filter("." + topics).show();
});
$(".sort-options select").change(function() {
var topics = '';
$(".sort-options select").each(function() {
if ($(this).val()) { // Create combined class .opt1.opt2.opt3
topics += "."+$(this).val();
}
});
$(".list-schools li").each(function() {
$(this).toggle($(this).is(topics));
});
});

Modify function to filter by several data-attributes simultaneously

The function below allows users to filter products by data-attributes, and accommodates filtering by multiple values simultaneously. It does this by creating an array of the values selected, and when any of the values are clicked (in this case checked/unchecked) it hides all the items and then re-shows those that match the values in the updated array.
It works correctly when filtering for one data-attribute, but when combined to filter by more than one attribute it no longer shows all results matching any of the values and instead only shows results matching all the specified values.
I've posted a fiddle which demonstrates the problem here: http://jsfiddle.net/chayacooper/WZpMh/94/ All but one of the items have the values of both data-style="V-Neck" and data-color="Black" and they should therefore remain visible if either of the filters are selected, but if another value from a different data-attribute some of the items are hidden.
$(document).ready(function () {
var selected = [];
$('#attributes-Colors *').click(function () {
var attrColor = $(this).data('color');
var $this = $(this);
if ($this.parent().hasClass("active")) {
$this.parent().removeClass("active");
selected.splice(selected.indexOf(attrColor),1);
}
else {
$this.parent().addClass("active");
selected.push(attrColor);
}
$("#content").find("*").hide();
$.each(selected, function(index,item) {
$('#content').find('[data-color *="' + item + '"]').show();
});
return false;
});
$('#attributes-Silhouettes *').click(function () {
var attrStyle = $(this).data('style');
var $this = $(this);
if ($this.parent().hasClass("active")) {
$this.parent().removeClass("active");
selected.splice(selected.indexOf(attrStyle),1);
}
else {
$this.parent().addClass("active");
selected.push(attrStyle);
}
$("#content").find("*").hide();
$.each(selected, function(index,item) {
$('#content').find('[data-style *="' + item + '"]').show();
});
return false;
});
});
Both of your handlers are updating the selected array, but only one handler executes on a click. The first one if a color was (de)selected, the second if a style. Let's say you've clicked on "Black" and "Crew Neck". At that time your selected array would look like this: [ "Black", "Crew_Neck" ]. The next time you make a selection, let's say you click "Short Sleeves", the second (style) handler executes. Here's what is happening:
Short_Sleeves gets added to the selected array.
All of the items are hidden using $("#content").find("*").hide();
The selected array is iterated and items are shown again based on a dynamic selector.
Number 3 is the problem. In the above example, a style was clicked so the style handler is executing. Any items in the selected array that are colors will fail because, for example, no elements will be found with a selector such as $('#content').find('[data-style *="Black"]').show();.
I would suggest 2 things.
Keep 2 arrays of selections, one for color, one for style.
Combine your code to use only a single handler for both groups.
Here's a (mostly) working example.
Note that I added a data-type="color|style" to your .filterOptions containers to allow for combining to use a single handler and still know which group was changed.
Here's the full script:
$(document).ready(function () {
// use 2 arrays so the combined handler uses correct group
var selected = { color: [], style: [] };
// code was similar enough to combine to 1 handler for both groups
$('.filterOptions').on("click", "a", function (e) {
// figure out which group...
var type = $(e.delegateTarget).data("type");
var $this = $(this);
// ...and the value of the checkbox checked
var attrValue = $this.data(type);
// same as before but using 'type' to access the correct array
if ($this.parent().hasClass("active")) {
$this.parent().removeClass("active");
selected[type].splice(selected[type].indexOf(attrValue),1);
}
else {
$this.parent().addClass("active");
selected[type].push(attrValue);
}
// also showing all again if no more boxes are checked
if (attrValue == 'All' || $(".active", ".filterOptions").length == 0) {
$('#content').find('*').show();
}
else {
// hide 'em all
$("#content").find("*").hide();
// go through both style and color arrays
for (var key in selected) {
// and show any that have been checked
$.each(selected[key], function(index,item) {
$('#content').find('[data-' + key + ' *="' + item + '"]').show();
});
}
}
});
});
UPDATE: incorporating suggestions from comments
To make the handler work with checkboxes instead of links was a small change to the event binding code. It now uses the change method instead of click and listens for :checkbox elements instead of a:
$('.filterOptions').on("change", ":checkbox", function (e) {
// handler code
});
The "All" options "hiccup" was a little harder to fix than I thought it would be. Here's what I ended up with:
// get a jQuery object with all the options the user selected
var checked = $(":checked", ".filterOptions");
// show all of the available options if...
if (checked.length == 0 // ...no boxes are checked
|| // ...or...
checked.filter(".all").length > 0) // ...at least one "All" box is checked...
{
// remainder of code, including else block, unchanged
}
I also added an all class to the appropriate checkbox elements to simplify the above conditional.
Updated Fiddle

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.

How do I manipulate a jqGrid's search/filters?

I have a jqGrid with a navBar that has search: true and multipleSearch: true. I would like to add a button to my UI that automatically adds an additional rule to the search.
I've tried manipulating the postData for the filter directly, but values added this way don't show up in the search UI.
I've also tried accessing the search box directly using jQuery, like this:
$('#fbox_list').searchFilter().add();
$('#fbox_list .sf .data input').each(function(index) {
alert($(this).val());
});
But, in addition to feeling hackish, it only works if the user has already clicked on the search button (the fbox_list div is not constructed on load).
Has anyone else dealt with an issue like this?
For the sake of posterity, here is the hack I'm currently using. The grid has an ID of list and the pager has an ID of pager:
jQuery(document).ready(function() {
//Initialize grid.
//Initialize the navigation bar (#pager)
//Hack to force creation of the search grid.
//The filter's ID is of the form #fbox_<gridId>
jQuery('#pager .ui-icon-search').click();
jQuery('#fbox_list').searchFilter().close();
//Example button events for adding/clearing the filter.
jQuery("#btnAddFilter").click(function() {
//Adds a filter for the first column being equal to 'filterValue'.
var postFilters = jQuery("#list").jqGrid('getGridParam', 'postData').filters;
if (postFilters) {
$('#fbox_list').searchFilter().add();
}
var colModel = jQuery("#list").jqGrid('getGridParam', 'colModel');
//The index into the colModel array for the column we wish to filter.
var colNum = 0;
var col = colModel[colNum];
$('#fbox_list .sf .fields select').last().val(col.index).change();
$('#fbox_list .sf .data input').last().val('filterValue');
$('#fbox_list .sf .ops select.field' + colNum).last().val('eq').change();
$('#fbox_list').searchFilter().search();
});
jQuery("#btnClearFilter").click(function() {
$('#fbox_list').searchFilter().reset();
});
});
If you mean the filter toolbar, you can do this: (status is the col name -- so, replace "#gs_status" w/ "#gs_" + your_col_name
jQuery("#distributor_grid").jqGrid('showCol',['status']);
jQuery(".ui-search-toolbar #gs_status")
.val('ALL')
;
$('#distributor_grid').RefreshData(); // triggers toolbar
to clear inputs, selects and reset grid
$("td#refresh_navGrid").click();

Categories