I have a problem with select input items.
What I want to achieve is dynamically remove already selected options from other select boxes so that I cannot select same item on multiple boxes. The problem is that elements are loaded in array via AJAX and I need to fill the select input with options after. This makes it so much harder.
In short - How can I make sure that if I select one item in select it will be deleted on all others, but when I select something else the previous item will be shown again and so on...
I have a fiddle as well, this is how far I got: http://jsfiddle.net/P3j4L/
You can try something like this
function updateSelects()
{
$('.selectContainer .select').each(
function (i, elem)
{
// Get the currently selected value of this select
var $selected = $(elem).find("option:selected");
// Temp element for keeping options
var $opts = $("<div>");
// Loop the elements array
for (i = 0; i < selectElements.length; i++)
{
var value = selectElements[i];
// Check if the value has been selected in any select element
if ($selected.val() == value || !$('.select option[value=' + value + ']:selected').length)
{
// if not create an option and append to temp element
$opts.append('<option value="' + value + '">' + value + '</option>');
}
}
// replace the html of select with new options
$(elem).html($opts.html());
if ($selected.length)
{
// set the selected value if there is one
$(elem).val($selected.val());
}
else
{
// new select element. So remove its selected option from all other selects
$('.selectContainer .select').not(this).find('option[value=' + $(elem).val() + ']').remove();
}
}
);
}
see a demo here : http://jsfiddle.net/P3j4L/1/
Related
I'm doing an autocomplete functionality which fills a datalist with options comprised of an endpoint query, which is working properly. But I have a problem in the end of my ajax call where my function is affecting only the last element of an array, as opposed to the correct one that is being clicked. I'm trying to make sure that when the user clicks their selection in the list, it sends certain values of the object into form input fields to save.
Right now, when i click an option it does put the correct object values into the form, HOWEVER, they are the values that correspond to the final element in the array and not the clicked one.
I've commented where my issue starts, but this is the whole script for reference. Again, the list fills correctly (though a little slow) and the click does fill out the form inputs, but the values are not corresponding to the clicked option, just the last in the array.
What am I doing wrong here?
<script type="text/javascript">
//If user types, send their input in ajax POST on each keystroke
$('#productInput').on('input', function(){
if($(this).val() === ''){
return;
}else{
//their input is searchResult
const searchResult = $(this).val();
$.ajax({ //url
data: {
search_result:searchResult
},
type: "POST",
success: function(response){
//empty out old responses
$('#returnedProducts').empty();
//this starts my index
let searchResult = response.hits.hits;
for(let i = 0; i < searchResult.length; i++) {
//this puts matches into the datalist option, which works
$("#returnedProducts").append("<option value=" + searchResult[i]._source.category + ">" + searchResult[i]._source.category + "</option>");
/*This block is my issue*/
$("#productInput").on('input', function(){
var val = this.val = this.value;
if($('#returnedProducts option').filter(function(){
return this.value === val;
}).length){
//These elements do fill, but the values correspond to only the last array item, not the clicked one
document.getElementById("grpName").value = searchResult[i]._source.frm.grp.grp_name;
document.getElementById("grpNum").value = searchResult[i]._source.frm.grp.grp_code;
}
})
/*end of problem block*/
}
}
});
}
});
</script>
The problem is that for each search result which is returned, you add another "input" event handler function to the "productInput" element. So if there are 5 results, you create 5 more event handlers. Then when something is input into that box, all 5 handlers (plus the original one, so 6) will execute in sequence. Since each time it overwrites the same textboxes, hence you only ever see the the last value. I'm pretty sure that's not even close to what you wanted.
You're adding options to the "returnedProducts" select list, and when the user selects an option you want some data to go into a form, is that right? If so, it would make more sense to handle the "change" event of the select list (and handle it once outside of your "success" function!!), and set data attributes on the option for the extra values. When the change event runs, retrieve the data attributes from the currently selected option and use those to populate your form.
Here's the general idea:
In the loop through your results:
for(let i = 0; i < searchResult.length; i++) {
//this puts matches into the select list option
$("#returnedProducts").append("<option value='" + searchResult[i]._source.category + "' data-grpName='" + searchResult[i]._source.frm.grp.grp_name + "' data-grpNum='" + searchResult[i]._source.frm.grp.grp_code + "'>" + searchResult[i]._source.category + "</option>");
}
Then separately (outside your $('#productInput').on('input', function(){ block entirely):
$("#returnedProducts").change(function() {
var selectedOption = $(this).find("option:selected");
$("#grpName").val(selectedOption.data("grpName"));
$("#grpNum").val(selectedOption.data("grpNum"));
});
I'll try to keep it at simple as I can.
I have a JSON object that is pulled via AJAX. I am displaying a list of icons in a main div from the data dynamically which can be toggled on or off.
I have a secondary div where the selected items are appearing, while the main div icon receives a class of active.
I want the end user to be able to remove any of them by clicking on them on either the main div or secondary div.
Most of this is working, but I'm having trouble figuring out the best way to map them together so that I have 2 separate click events which can control the same outcome.
I think it may have something to do with the fact that I'm dynamically creating elements... which create more elements... which have to alter the initial elements.
My structure so far is to map the current selection inside of an array. This gives me control over keeping a code-based list of everything that is selected (there is much more data than in the example I'll be providing).
So, here is how I have it so far:
HTML:
<div id="options"></div>
<div id="selectedOptions"></div>
Javascript/jQuery:
// Simple simulated AJAX data
var ourData = {
"color1": "yellow",
"color2": "blue"
};
var $options = $('#options');
var $selectedOptions = $('#selectedOptions');
// Array to keep track of which objects are selected
var selectedOptions = [];
// Makes the initial option dynamic list
makeOptions(ourData, $options);
// If an option from the main div is clicked, handle class changing
$('button').on('click', function(){
pickOption($(this));
});
/* This function is the problem. The option gets removed from the array, and from the secondary div, but the class of active still occurs on the main div. */
$selectedOptions.on('click', '.optionActive', function(){
var option = $(this).data('color');
var optionPosition = jQuery.inArray(option, selectedOptions);
selectedOptions.splice(optionPosition, 1);
displayOptions(selectedOptions, $selectedOptions);
});
// Creates initial icons (buttons in this case) to the DOM and applies a data-attribute for the color
function makeOptions(options, $container){
var $results = $('<div id="results">');
$.each(options, function(key, value){
var $optionButton = $('<button>' + key + ':' + value + '</button>');
$optionButton.data('color', value);
$results.append($optionButton);
});
$container.append($results);
}
/* Handler for selecting an option from the Main Div. Handling the class active.
I am not using a simple classToggle because there are many situations where a click is not allowed */
function pickOption($option){
var selectedOption = $option.data('color');
// If the option returns true, or that it doesn't exist yet
if(modifyOptions(selectedOption, selectedOptions)){
$option.addClass('active');
} else {
$option.removeClass('active');
}
// Recreate our current selected options
displayOptions(selectedOptions, $selectedOptions);
}
/* Searches array to see if the option exists. Returns true or false and either pushes or splices the option from the array */
function modifyOptions(option){
var optionPosition = jQuery.inArray(option, selectedOptions);
if(optionPosition == -1){
selectedOptions.push(option);
return true;
} else {
selectedOptions.splice(optionPosition, 1);
return false;
}
}
/* Displays all currently selected options that exist in our array */
function displayOptions(selectedOptions, $container){
$container.empty();
$.each(selectedOptions, function(option, value){
var $optionTile = $('<div class="optionActive">');
$optionTile.data('color', value)
.text(option + ":" + value)
.css('background', value);
$container.append($optionTile);
});
}
So, to summarize, I want some some way to remove the .active class from the main div equivalent element when the item from the second div is clicked.
I tried removing the class active by searching for any elements with the data-color=data-color of the selected item, but I couldn't get that to work.
ex:
$('*[data-color="' + $(this).data('color') + '"]').removeClass('active');
I would really like some data approach to this, such as removing the class active if it had data-color="yellow" for instance.
Playground:
https://jsfiddle.net/c75xcLha/
EDIT:
Both Are Selected, working as designed:
Clicked Yellow Div. Yellow Button is still active:
Should remove the active class from the button when the yellow div OR the button is pressed, as shown here:
You are assigning data-* property using .data(PROP), not attribute hence element having data-* property could not be accessed/selected using attribute-selector, assign attribute using .attr('data-color') instead of .data(property)
Attribute Equals Selector [name=”value”], Selects elements that have the specified attribute with a value exactly equal to a certain value.
.data( key, value ), Store arbitrary data associated with the matched elements.
When you use .data() to update a data value, it is updating internal object managed by jQuery, so it will not be updated in the data-* attribute[Ref]
// Simple simulated AJAX data
var ourData = {
"color1": "yellow",
"color2": "blue"
};
var $options = $('#options');
var $selectedOptions = $('#selectedOptions');
// Array to keep track of which objects are selected
var selectedOptions = [];
// Makes the initial option dynamic list
makeOptions(ourData, $options);
// If an option from the main div is clicked, handle class changing
$('button').on('click', function() {
pickOption($(this));
});
/* This function is the problem. The option gets removed from the array, and from the secondary div, but the class of active still occurs on the main div. */
$selectedOptions.on('click', '.optionActive', function() {
var option = $(this).data('color');
var optionPosition = jQuery.inArray(option, selectedOptions);
selectedOptions.splice(optionPosition, 1);
$('[data-color="' + $(this).data('color') + '"]').removeClass('active');
displayOptions(selectedOptions, $selectedOptions);
});
// Creates initial icons (buttons in this case) to the DOM and applies a data-attribute for the color
function makeOptions(options, $container) {
var $results = $('<div id="results">');
$.each(options, function(key, value) {
var $optionButton = $('<button>' + key + ':' + value + '</button>');
$optionButton.attr('data-color', value);
//___________^^^^^^^^^^^^^^^^^^Little trick here!
$results.append($optionButton);
});
$container.append($results);
}
/* Handler for selecting an option from the Main Div. Handling the class active.
I am not using a simple classToggle because there are many situations where a click is not allowed */
function pickOption($option) {
var selectedOption = $option.data('color');
// If the option returns true, or that it doesn't exist yet
if (modifyOptions(selectedOption, selectedOptions)) {
$option.addClass('active');
} else {
$option.removeClass('active');
}
// Recreate our current selected options
displayOptions(selectedOptions, $selectedOptions);
}
/* Searches array to see if the option exists. Returns true or false and either pushes or splices the option from the array */
function modifyOptions(option) {
var optionPosition = jQuery.inArray(option, selectedOptions);
if (optionPosition == -1) {
selectedOptions.push(option);
return true;
} else {
selectedOptions.splice(optionPosition, 1);
return false;
}
}
/* Displays all currently selected options that exist in our array */
function displayOptions(selectedOptions, $container) {
$container.empty();
$.each(selectedOptions, function(option, value) {
var $optionTile = $('<div class="optionActive">');
$optionTile.data('color', value)
.text(option + ":" + value)
.css('background', value);
$container.append($optionTile);
});
}
.active {
background: #CCF;
}
.optionActive {
min-width: 100px;
min-height: 100px;
display: inline-block;
margin: 1em;
background: #eee;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div id="options"></div>
<div id="selectedOptions"></div>
Updated Fiddle
Edit: If you still want to stick with .data method, use .filter to select target element.
$('button').filter(function(){
return $(this).data('color')=='yellow';
}).removeClass('active');
I have this page depending on the val on the top of the page, select check boxes are shown or hidden.
If Value is VAL then check boxes are shown and only after selecting the check box, values get populated in the text area. So far it works.
Now if the Value is MAR then the check boxes will be hidden. This is where values are not populating in the text area.
Help is much appreciated. FIDDLE
$('table').find("input[type=radio]:checked:enabled").each(function () {
if($('table').find("input[type=checkbox][name='" + $(this).attr('name') + "']").is(':checked')) {
// See if we have a text box, if so use the text
var $text = $(this).parent().find('textarea.m-notes:visible');
var missingReason = $(this).parent().find('.reason').val();
// Find closest ancestor with an id
var selectedId = $(this).closest('[id]').attr('id');
var value = selectedId + "~" + $(this).val();
if ($text.length)
{
value += "~" + missingReason +"~" + $text.val();
}
clicked.push(value);
}
}); //checked
// Display the selected ids
$("#inputhere").val(clicked.join('|'));
}
var options = $('#mobility-table').find('select.MobilityCountry[data="'+selectionId+'"]').data('options').filter('[data="' + id + '"]');
options.sort(function(a,b) {
if (a.innerHTML > b.innerHTML) return 1;
else if (a.innerHTML < b.innerHTML) return -1;
else return 0;
The above code will give me all the list of cities upon selecting a country. I would like to add a default value 'All' at the first place in the variable 'options'. Can any one suggest me how to add this. Any help greatly appreciated. Thankyou.
Ex: options should have 'All,London,Scotland,Stanmore, Watford'.
You can use unshift() to add an element to the beginning of the sorted array:
If you're just trying to add text to the first element, it would be like this:
options.sort(function(a,b) {
if (a.innerHTML > b.innerHTML) return 1;
else if (a.innerHTML < b.innerHTML) return -1;
else return 0;
}
options.unshift("All");
If you want to add an option element to the array, it would be like this:
var item = document.createElement("option");
item.value = "all";
item.innerHTML = "All";
options.unshift(item);
It isn't clear to me whether you're also trying to change your HTML. If so, then please show what your HTML looks like so we can advise how to add that element to the DOM. It's not clear to me what HTML item is the select item.
In jQuery, you could add the option to be the first item in the drop-down like this
// you have to fill in the appropriate selector for your select object
$("#selector for select object").prepend("<option value='all'>All</option>");
unshift() a new <option>:
var option = document.createElement("option");
option.value = "all";
option.appendChild(document.createTextNode("All"));
options.unshift(option);
jQuery:
options.unshift($("<option>", {text: "All", value: "all"}).get(0));
I am trying to access each individual element, ie option, defined for a list box (or drop down box).
For some reason the code I am using is not working. It is given below---
$(jQuery('input', $(this).parent('form'))).each(function() {
element= $(this);
textmsg=" Element # " + (count+1) + "...Name of this input element = " + $(this).attr('name') + " multiplechoice-" + $(this).attr('multiple');
textmsg= textmsg + "...Also, for this element, the value is " + $(this).val() + " and type =" + $(this).attr('type');
alert (textmsg);
var listofoptions = new Array();
type=$(this).attr('type');
if(type=="select")//this means we have to go through the children for this select element, to obtain the values for each option
{
var elements= $('option', this);
for(var i=0; i<elements.length; i++)
{
// add $(this).val() to your list
alert("Value of this option=" + $elements[i].val());
});
}
});
How do I make the above code work? Or can you suggest an alternative way of accessing each option value? Thanks...
In order to select all inputs you would need to use the :input selector and not just $('input') as this will select inputs by tag name and the select will be excluded.
So do
$(this).parent('form').find(':input')
Also, since there's no type attribute on a select element. You could use .is() instead to check if it's a select.
$(this).is('select')
Edit: for the if statement i would do the following
if( $(this).is('select') )
{
$(this).find('option').each(function(){
alert( $(this).val() );
});
}
Here's a fiddle
the select tag is not an input so it would never be a part of the selection
You could try
$("input, select")