jQuery $.change function not working with cloned select - javascript

I have a table with a button that adds a row to the bottom by cloning the last row. Each row contains a <select> with a different name (0-9), all <select> objects have the .variable_priority class. When pressing the button, the row gets copied successfully and I manage to change the name correctly (10, 11, 12, etc.), and the row gets the same class since it is a perfect copy.
However, when I execute the following function, I encounter problems with cloned table rows:
$('.variable_priority').change(function() {
var selections = new Array();
$(".variable_priority").each(function() {
selections.push($(this).find('option:selected').val());
});
// Iterating on Options of Select
$('.variable_priority').children('option').each(function() {
$(this).removeAttr('disabled');
if($.inArray($(this).val(), selections) !== -1){
if($(this).val() != 0){
if($(this).is(':selected')){
// nothing
} else {
$(this).attr('disabled', true);
}
}
}
});
});
The function should run each time I change the selected option of a <select>, though it only runs with the 10 original ones. This function is not executed when I change the option in a cloned row. However, if I change the value in one of the originals, the function runs and it also adds the values from the cloned rows to the selections array.
So for some reason, the code recognizes that the clones have the same class, but it doesn't run when changing their values.
EDIT: short description of the code above; if I change the selected value of a <select>,the function will add all selected options to an array and disable every selected option in the selects, except in the box where the value itself is selected (if I select '2' in the first box, '2' gets disabled in all other boxes).

Because your select element is dynamic (It is added to the DOM after the initial page load, or to be specific; after the initial event handler attachment) you will need to delegate your change event handler:
$(document).on('change', '.variable_priority', function() {
});
Rather than use document though, you'll want to attach the event handler to the closest static element to .variable_priority.
JSFiddle

I think the code isn't executed on the new clones.
This script is loaded on start. It has to do it over for each new children.. Maybe after adding a new, run this script specific for that new one.

Related

Understanding jQuery .change event

I have some issue understanding the jQuery().change() behavior.
The HTML is basically a lot of input elements - checkboxes ( each with ID of id^='o99-post-visible-XXX' - and they are pure CSS images as Checkboxes, but this is irrelevant ) and I have another checkbox ("#o99-check-all") to "check all" and a text input field ('#o99-post-visible-ids') that receives the IDs of the selected boxes.
The jQuery code is as follows:
jQuery(document).ready(function() {
jQuery("#o99-check-all").change(function () {
jQuery("input:checkbox[id^='o99-post-visible-']").prop('checked', jQuery(this).prop("checked")).trigger('change');
});
var checkboxes = jQuery("input.o99-cbvu-posts-checkbox:checkbox");
checkboxes.on('change', function() {
// get IDS from all selected checkboxes and make a comma separated string
var ids = checkboxes.filter(':checked').map(function() {
return this.value;
}).get().join(',');
// put IDS inside a text input field
jQuery('#o99-post-visible-ids').val(ids);
// console.log(ids);
});
});
Now, more or less everything works now, but that is not the issue.
at first , the first chunk of code was:
jQuery("#o99-check-all").change(function () {
// without .trigger('change') chained
jQuery("input:checkbox[id^='o99-post-visible-']").prop('checked', jQuery(this).prop("checked"));
});
and it did not work ( why?? ) - meaning the boxes were selected as expected but the '#o99-post-visible-ids' input field was not receiving the IDs - until I chained a .trigger('change') event - when suddenly it works well.
my confusion is with the following ( which perhaps for my little understanding of jQuery internal works is counter-intuitive )
after chain adding .trigger('change') - isn't it somehow an endless loop where a chain() event is trigger inside a listener of change() ? and if not why?
Why is the code functioning now and did not function correctly before? because again, for my understanding, there was a change, even if not triggered by direct user click. Why would I need to trigger it manually?
I'm not sure I understand what you mean. What is happening now, is that whenever you change the all checkbox, the other checkboxes will be checked/unchecked the same as all, and then the change event is triggered.
Because you added a listener for change, that function will then fire. I.e. this function will run:
function() {
// get IDS from all selected checkboxes and make a comma separated string
var ids = checkboxes.filter(':checked').map(function() {
return this.value;
}).get().join(',');
// put IDS inside a text input field
jQuery('#o99-post-visible-ids').val(ids);
// console.log(ids);
}
Without your .trigger("change") (or .change() in short), you only change a property of the inputs. So the object changes, indeed, but that does not mean the change event is triggered. It does sound counter-intuitive, but events are only triggered by user actions or if you call the event explicitly - in no other way do events get triggered.
its because you have written jQuery('#o99-post-visible-ids').val(ids); inside a function which happens only when the change event done on the inputs, assigning prop directly through .prop does not trigger the change event and so the result handler wont run
Now if I understand you correctly...
...because you're giving every check box the same ID? If you wish to apply it to more than a single element, it is best practice to use a class selector instead.
jQuery(".o99-check-all").change(function () {
// without .trigger('change') chained
jQuery(".o99-check-all").prop('checked', jQuery(this).prop("checked"));
});
See link
https://api.jquery.com/change/

Html select not changes option on click after jquery instant filter in jsp

I have 3 select tags on one page, generated from struts2 select tag. I am using a jQuery filter function that filters the select. One textfield for every select, but all of them use the same filter function. I have another js function that is called on onChange event.
The problem is that before adding this jQuery function i was filtering the lists with form submit and reload the page and now the filtration happens instant, but when i write a filtration criteria the select somehow the select loses focus and when i click an element no select happens, or better lets say is a kind of select: the element is circled with a dotted line, not selected with a blue filled square. The js is called, the form submitted, but with the old value. However, if i first click in the select where are no elements (empty zone) and then i select an element everything is ok. How can i jump over the firs click?
And now my code:
I. The jQuery filter function and the binding to the selects and textfields.
jQuery.fn.filterByText = function(textbox) {
return this.each(function() {
var select = this;
var options = [];
$(select).find('option').each(function() {
options.push({value: $(this).val(), text: $(this).text()});
});
$(select).data('options', options);
$(textbox).bind('change keyup', function() {
var options = $(select).empty().scrollTop(0).data('options');
var search = $.trim($(this).val());
var regex = new RegExp(search,'gi');
$.each(options, function(i) {
var option = options[i];
if(option.text.match(regex) !== null) {
$(select).append($('<option>').text(option.text).val(option.value));
}
});
});
});
};
$(function() {
$('#selectedClientId').filterByText($('#filterClient'));
$('#selectedLocationId').filterByText($('#filterLocation'));
$('#selectedViewPointId').filterByText($('#filterViewpoint'));
});
II. One of the selects:
<s:select size="10" cssStyle="width:220px;"
label="Select a client"
listKey="id" listValue="name"
list="clientSelectList"
name="selectedClientId" id="selectedClientId"
headerKey="-1" headerValue="Client List"
onchange="onChangeSelect()"
/>
III. The select's textfield:
Filter:<s:textfield name="filterClient" id="filterClient" size="15" autocomplete="off"/>
IV. The onChangeSelect():
function onChangeSelect() {
document.getElementById('deviceListForm').action = '<s:url value="/admin/displayDeviceListPage.action"/>';
document.getElementById('deviceListForm').submit();
}
In the image: in the first select is how looks the selected option after jquery filter and in the other 2 selects are "the good" selected options.
http://i.stack.imgur.com/TAJeY.png
EDIT: So, after the first response to this post (Thanks Amit1992) I started digging further. In Mozilla after the first click (after the frame or dotted line appears) a request is made to the server with the old selected item (or null if none selected), the page refreshes as nothing happened.
In Chrome, on the other hand, the first click does not make any request. It just selects (let's say) the select tag. And the second select makes a good request.
Short story:
mozilla: click 1 -> request with old selected value ->refresh -> no changes
chrome: click 1 -> selects the select tag and no request is made -> click 2 -> request as it should happen
IE - works ok. 1 click-> select and load page as it should . OK this really surprises me. at first I thought is useless to look in IE what happens.
EDIT2
After some digging i concluded that the problem is that when typing in the textfield the select loses focus. If I put $('#selectedClientId').focus();
in the filterByText function at the end of the $(textbox).bind('change keyup', function() the fist select is focused after every char written. But this gives me another problem. I can't write more than 1 char at a time. I have to click the textfield, write a char, click again, write a char etc.
May be this will help you. i did some modification in your code.
$(function() {
$('#selectedClientId').filterByText($('#textbox'), false);
$("#selectedClientId").change(function(){
alert("you have selected ++ " + $(this).val());
});
});
I used change() event of jquery instead of javascript onChange().
you can refer this link http://jsfiddle.net/amitv1093/q55k97yc/ and I recommend you to use jquery fully if you are using it.
kindly let me know if it will work.
I solved the problem by changing the whole filter function. The function with problem was taken from a stack overflow question response (How to dynamic filter options of <select > with jQuery?). The problem is, from what I concluded, that the $(textbox).bind('change keyup', function() line was changing the focus on the textfield, so the first click was changing the focus to the select tag. The new function, the one that works was taken from the same post, John Magnolia's answer:
$(document).ready(function() {
filterClient();
filterLocation(); //same as filterClient
filterViewpoint(); //same as filterClient
});
function filterClient(){
var $this, filter,
$input = $('#filterClient'),
$options = $('#selectedClientId').find('option');
$input.keyup(function(){
filter = $(this).val();
$options.each(function(){
$this = $(this);
$this.removeAttr('selected');
if ($this.text().toLowerCase().indexOf(filter.toLowerCase()) != -1) {
$this.show();
} else {
$this.hide();
}
});
});
}

JQuery Syntax Check -- Array Data

var selections = [];
$dragContainerDiv1.on("click", ".draggable1", function (event) {
event.stopPropagation();
var $this = $(event.target);
if ($this.hasClass("selected")) {
$this.removeClass("selected");
selections.splice(selections.indexOf($this), 1);
}
else {
selections.push($this);
$this.addClass("selected");
initDraggable($this);
}
});
My arrays don't seem stable and I'm thinking it's because my jQuery syntax is not right. The click event is occurring on a list of div tags which contain text, data-id, and data-text. The idea is to be able to multi-select the draggable divs.
So, when initially clicked, it adds the div to the array and highlights it. When clicked again, it removes the div from the array. Eventually, the group of selected divs are dragged to the drop zone, where I recover the data and post it to the server.
If I click rapidly through multiple divs, it appears that the selected divs are not always the ones in the array.
Your removing of $this from your selections array isn't working. selections.indexOf($this) is always returning -1, and therefore your selections.splice(-1, 1) is removing the last element from selections. What you want to store in selections is the element contained in the $this object:
selections.push($this[0]);
And when removing:
selections.splice(selections.indexOf($this[0]), 1);

Using Jquery, load select options on focus

I am trying to load options into a select element when the user focuses.
Here is the jquery code I'm using:
$('select').focus(function() {
var $this = $(this);
if (!$this.data('hasitems')) {
var selectedValue = $this.val();
$this.empty()
.append($('<option></option')
.attr('value','')
.text('Loading...'));
// This would usually be the result of an AJAX call
$this.empty()
.data('hasitems','true');
$.each(['a','b','c','d'], function(index,item) {
$this.append($('<option></option>')
.attr('value',item)
.text(item)
.prop('selected', selectedValue == item));
});
}
});
Here is the fiddle:
http://jsfiddle.net/agnnC/
The solution almost works... except in Firefox (and sometimes not in Chrome either, although the fiddle I put together does appear to work).
The problem in Firefox is that when the user clicks on the select element, the currently selected value is not remembered and is changed to one of the new values in the drop down.
Can anyone think of a workaround?
I think the issue is that the selected attribute is not really a property the way you are using it. Per the MDN doc:
selected
If present, this Boolean attribute indicates that the option is
initially selected. If the element is the descendant of
a element whose multiple attribute is not set, only one single
of this element may have the selected attribute.
Note, it talks about "initially selected" only, not real time changes. It also refers to selected only as an attribute, not a property.
The W3C spec for the option element also talks only about pre-selecting an option, not about making live changes using the selected attribute.
Once the select and options are live, the .selectedIndex property on the <select> object controls which option is selected in real time for single selection select elements.
In support of this theory, if you change to setting the saved item with .selectedIndex as shown below, the problem goes away:
$('select').focus(function() {
var $this = $(this);
if (!$this.data('hasitems')) {
var selectedValue = $this.val();
$this.empty()
.append($('<option></option')
.attr('value','')
.text('Loading...'));
// This would usually be the result of an AJAX call
$this.empty()
.data('hasitems','true');
$.each(['a','b','c','d'], function(index,item) {
$this.append($('<option></option>')
.val(item)
.text(item));
if (selectedValue == item) {
$this.prop("selectedIndex", index);
}
});
}
});
Working demo: http://jsfiddle.net/jfriend00/4333d/
Firefox can't change the focus option when select is opening, but you can change before it open, change the event to mousedown it working Fiddle
$('select').mousedown(function() {
// ...
});

How to trigger an event ONLY if both dropdowns are selected?

I have a dropdown select list on my page of class="TypeFilter".
I have a jQuery event that fires when a value in that list is selected.
$(".TypeFilter").change(function()
{
// Extract value from TypeFilter and update page accordingly
));
I now have to add another list to the page, and I want to implement functionality which will prevent the .change(function() from running unless both are selected.
In both lists the first option in the list is some text instructing the user to select one of the items, so I was thinking of just writing some logic to test that both lists have a selected index greater than 0.
I think this is a touch unclean though, especially considering that other pages that have a TypeFilter use the same logic.
Is there any nifty functionality in jQuery that can do this?
edit I should specify that the user needs to be able to update the page by selecting either dropdown, so I can't put the onchange on the second element and test that the first element has a selected value, as suggested in one of the answers
If you bind the same event to all dropdowns, you can get a collection of all the dropdowns and check that all of them are selected. Example:
$('.Dropdown').change(function(){
var elements = $('.Dropdown');
if (
elements.filter(function(){
return this.selectedIndex > 0;
}).length == elements.length
) {
// all dropdowns are selected
}
});
As you partly mention, put the onchange on the second element and test that the first element has a selected value before you fire off any logic.
Use bind instead, and as the eventdata, send a function that checks that either that both are selected or that the other is selected. Untested code:
function checker() {
// test your conditions
}
$(".TypeFilter").bind('change', {test: checker}, function(event)
{
if (event.data.test && event.data.test()) {
// Extract value from TypeFilter and update page accordingly
}
));
This way the other pages that use the same function will not notice any changes.

Categories