Stop multiple select from scrolling to top when selection changes - javascript

I have a multi select list that i use to filter a grid with. When i select or deselect any item in the list, it triggers an event.
The problem is that when i scroll down and select or deselect a value lower on the list, it jumps back to the top. How can i stop this from happening?
I've made a fiddle: https://jsfiddle.net/Berge90/a2two97o/
Edit: Problems in Chrome. Works fine in Edge and Firefox
HTML
<div class="FilterContainer">
<select id="SelectTenant" multiple="true">
</select><br/>
<button onclick="setAllTenantSelections(true)">Select All</button>
<button onclick="setAllTenantSelections(false)">Select None</button>
</div>
Javascript
window.onload = setupFilter;
window.onload = populateTenantFilter;
gridHeaders = [{name: "Test"},{name: "Value"},{name: "Another one"},{name: "And another"},{name: "Last one"}];
//Selecting/Deselecting all values
function setAllTenantSelections(selected) {
var select = document.getElementById("SelectTenant");
for (element in select.children) {
select[element].selected = selected;
showCol(select[element].text, selected);
}
}
//Adding all values from array to list
function populateTenantFilter() {
var select = document.getElementById("SelectTenant");
select.innerHTML = "";
for (i = 0; i < gridHeaders.length; i++) {
var option = document.createElement("Option");
option.innerHTML = gridHeaders[i].name;
select.appendChild(option);
}
//setting all options as selected on load
setAllTenantSelections(true);
setupFilter();
}
//Adding onclick-events to the values
function setupFilter() {
$('select option').on('mousedown', function (e) {
this.selected = !this.selected;
if (this.selected) {
console.log("SELECTED: " + this.text);
showCol(this.text,true);
} else {
console.log("DESELECTED: " + this.text);
showCol(this.text,false);
}
e.preventDefault();
});
}
function showCol(){
//Filtering grid based on selection
}

I solved this by scrolling back to the original scrollTop in the next event loop:
$('.your-selector').mousedown(e => {
var el = e.target;
e.preventDefault();
// ...your code
// fixes erratic scroll behaviour in Chrome
var scrollTop = el.parentNode.scrollTop;
setTimeout(() => el.parentNode.scrollTo(0, scrollTop), 0);
});

Related

How to reset or unselect multi select box using jQuery?

I have one bootstrap tab and i create multi select box using jQuery and the all functions are working properly but the RESET button only not working.
i try my all ways but its waste, anyone can you help me..
Please check my full code on fiddle,
MY FULL CODE IS HERE
Just want how to reset the field using jQuery
(function($) {
function refresh_select($select) {
// Clear columns
$select.wrapper.selected.html('');
$select.wrapper.non_selected.html('');
// Get search value
if ($select.wrapper.search) {
var query = $select.wrapper.search.val();
}
var options = [];
// Find all select options
$select.find('option').each(function() {
var $option = $(this);
var value = $option.prop('value');
var label = $option.text();
var selected = $option.is(':selected');
options.push({
value: value,
label: label,
selected: selected,
element: $option,
});
});
// Loop over select options and add to the non-selected and selected columns
options.forEach(function(option) {
var $row = $('<a tabindex="0" role="button" class="item"></a>').text(option.label).data('value', option.value);
// Create clone of row and add to the selected column
if (option.selected) {
$row.addClass('selected');
var $clone = $row.clone();
// Add click handler to mark row as non-selected
$clone.click(function() {
option.element.prop('selected', false);
$select.change();
});
// Add key handler to mark row as selected and make the control accessible
$clone.keypress(function() {
if (event.keyCode === 32 || event.keyCode === 13) {
// Prevent the default action to stop scrolling when space is pressed
event.preventDefault();
option.element.prop('selected', false);
$select.change();
}
});
$select.wrapper.selected.append($clone);
}
// Add click handler to mark row as selected
$row.click(function() {
option.element.prop('selected', 'selected');
$select.change();
});
// Add key handler to mark row as selected and make the control accessible
$row.keypress(function() {
if (event.keyCode === 32 || event.keyCode === 13) {
// Prevent the default action to stop scrolling when space is pressed
event.preventDefault();
option.element.prop('selected', 'selected');
$select.change();
}
});
// Apply search filtering
if (query && query != '' && option.label.toLowerCase().indexOf(query.toLowerCase()) === -1) {
return;
}
$select.wrapper.non_selected.append($row);
});
}
$.fn.multi = function(options) {
var settings = $.extend({
'enable_search': true,
'search_placeholder': 'Search...',
}, options);
return this.each(function() {
var $select = $(this);
// Check if already initalized
if ($select.data('multijs')) {
return;
}
// Make sure multiple is enabled
if (!$select.prop('multiple')) {
return;
}
// Hide select
$select.css('display', 'none');
$select.data('multijs', true);
// Start constructing selector
var $wrapper = $('<div class="multi-wrapper">');
// Add search bar
if (settings.enable_search) {
var $search = $('<input class="search-input" type="text" />').prop('placeholder', settings.search_placeholder);
$search.on('input change keyup', function() {
refresh_select($select);
})
$wrapper.append($search);
$wrapper.search = $search;
}
// Add columns for selected and non-selected
var $non_selected = $('<div class="non-selected-wrapper">');
var $selected = $('<div class="selected-wrapper">');
$wrapper.append($non_selected);
$wrapper.append($selected);
$wrapper.non_selected = $non_selected;
$wrapper.selected = $selected;
$select.wrapper = $wrapper;
// Add multi.js wrapper after select element
$select.after($wrapper);
// Initialize selector with values from select element
refresh_select($select);
// Refresh selector when select values change
$select.change(function() {
refresh_select($select);
});
});
}
})(jQuery);
$(document).ready(function() {
$('select').multi({
search_placeholder: 'Search',
});
});
/* Reset button */
function DeselectListBox() {
var ListBoxObject = document.getElementById("firstData")
for (var i = 0; i < ListBoxObject.length; i++) {
if (ListBoxObject.options[i].selected) {
ListBoxObject.options[i].selected = false
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
You can trigger the click of your reset button and clear the whole div in your document ready function. After this you can remove the class "selected" so its completely reset.
Like this
$(document).ready(function() {
$('select').multi({
search_placeholder: 'Search',
});
$('#tabReset').click(function() {
$('.selected-wrapper').empty();
$('a').removeClass('selected');
});
});
attach an event to reset button. empty the selected-wrapper and remove the selected class from non-selected-wrapper
$("button.alltabreset").click(function(){
$(".selected-wrapper").empty();
$(".item").removeClass("selected");
});
solution: https://jsfiddle.net/zuov3wmb/

Javascript on change for checkbox

I am changing state of check boxes with following code:
document.getElementById('checkall').onclick = function(){
inputs = VARIABLE.querySelectorAll('input[type=checkbox]');
for(i=0; i<inputs.length; i++)
inputs[i].checked = true;
}
This section work fine.
and i am creating checkboxes with(these codes call on for):
mainFrameInput = document.createElement("input"); mainFrameInput.className = "item"; mainFrameInput.style.display='none'; mainFrameInput.setAttribute('type', 'checkbox'); mainFrameInput.setAttribute('id', GnId);
this section work fine too
At this time i want to have a function which run when check boxes changed because it can change on several way.
I am creating check boxes with JavaScript and want to handle onchange with JavaScript NOT JQUERY.
I tested CHECKBOX_VARIABLE.onchange = function{} but it does not call when i change with above code and just CHECKBOX_VARIABLE.onclick work when i click on each checkbox.
I found solution and posted as answer.
one way to do this is by using the native onchange attribute and give it a function
<select id="mySelect" onchange="alert('change')">
<option value="Audi">Audi</option>
<option value="BMW">BMW</option>
<option value="Mercedes">Mercedes</option>
<option value="Volvo">Volvo</option>
</select>
here's a fiddle showing this
https://jsfiddle.net/r4aj8zh2/
You can do this like that:
HTML:
<button id="checkall">check all</button><br>
a: <input type="checkbox" name="a" value="a"><br>
b: <input type="checkbox" name="b" value="b"><br>
c: <input type="checkbox" name="c" value="c">
JavaScript:
var inputs = document.querySelectorAll('input[type=checkbox]');
document.getElementById('checkall').onclick = function(){
for(var i=0; i<inputs.length; i++) {
inputs[i].checked = true;
}
somethingChanged();
}
for(var i=0; i<inputs.length; i++) {
inputs[i].addEventListener('change', somethingChanged);
}
function somethingChanged(evt) {
if (evt) {
console.log(evt.srcElement.name, 'changed');
}
else {
console.log('all changed');
}
}
Fiddle: https://jsfiddle.net/1m3rcvw9/
Explanation: When I tried it I could reproduce your problem - the change listener was not called when clicking the check-all button. So my idea is to just call the function manually after a click occurs on check-all. You can even distinguish between single checkbox clicks and check-all clicks by checking if there is a event-parameter.
EDIT: If you dynamically add <input> tags then just add the somethingChanged change listener right after creation of new elements and update the inputs variable by reselecting all checkboxes:
mainFrameInput = document.createElement("input");
mainFrameInput.addEventListener('change', somethingChanged);
// ... insert the element into DOM here
inputs = document.querySelectorAll('input[type=checkbox]');
You can addEventListener to these checkboxes
// Get all checkbox. Use more specific selector using name or class
var getAllCheckBox = document.querySelector('input[type=checkbox]');
// Adding event listener change to each checkbox
getAllCheckBox.addEventListener('change', function (event) {
if (getAllCheckBox.checked) {
// do something if checked
} else {
// do something else otherwise
}
});
Add event listener to element when element is created. Make sure the D is lower case d at .getElementById VARIABLE = document.getElementById('#div-id');
mainFrameInput = document.createElement("input");
mainFrameInput.addEventListener("change", function() {
// do stuff
})
FINALLY I RESOLVED THE ISSUE:
first of all i developed a function:
function fireEvent(element,event){
if (document.createEventObject){
var evt = document.createEventObject();
return element.fireEvent('on'+event,evt)
}
else{
var evt = document.createEvent("HTMLEvents");
evt.initEvent(event, true, true ); // event type,bubbling,cancelable
return !element.dispatchEvent(evt);
}
}
and called that when changed state of check box:
fireEvent(inputs[i],'change');
and added on change event when creating check boxes:
mainFrameInput.onchange = function(){
if (this.checked)
{
console.log('checked');
}
else
{
console.log('un checked');
}
}
I think it is more easy just define a onchange function into the input element like this:
const wrapperElement = document.querySelector('.wrapper')
const fruits = ['apple', 'orange', 'banana']
fruits.forEach(f => {
const item = document.createElement('div')
item.className = 'item'
const fruit = document.createElement('input')
fruit.type = 'checkbox'
fruit.id = f
fruit.onchange = handleOnChange
const label = document.createElement('label')
label.className = 'checkbox-label'
label.setAttribute('for', f)
label.textContent = f
item.append(fruit)
item.append(label)
wrapperElement.append(item)
})
function handleOnChange(e) {
const element = e.srcElement
element.parentElement.classList.toggle('checked')
}
.item.checked {
background: red;
}
<div class="wrapper"></div>

Cloning a JS element that contains a chained select

I've created a script to clone a div, which works fine, however but the javascript chained function within it no longer works for any cloned elements. Works ok for the first one as expected.
I've created a jsfiddle here: https://jsfiddle.net/bvcebmbw/
The javascript is as follows (for both chained and clone functions)
$(document).ready(function () {
$(".Targeting").each(function () {
$('#TargetingAdd').click(function () {
var num = $('.clonedTargeting').length, // Checks to see how many "duplicatable" input fields we currently have
newNum = new Number(num + 1), // The numeric ID of the new input field being added, increasing by 1 each time
newElem = $('#entryTargeting' + num).clone().attr('id', 'entryTargeting' + newNum).fadeIn('slow'); // create the new element via clone(), and manipulate it's ID using newNum value
// Insert the new element after the last "duplicatable" input field
$('#entryTargeting' + num).after(newElem);
// Enable the "remove" button. This only shows once you have a duplicated section.
$('#TargetingDel').attr('disabled', false);
init(newElem.children(".Targeting"));
// Right now you can only add 4 sections, for a total of 5. Change '5' below to the max number of sections you want to allow.
if (newNum == 5)
$('#TargetingAdd').attr('disabled', true).prop('value', "You've reached the limit"); // value here updates the text in the 'add' button when the limit is reached
});
$('#TargetingDel').click(function () {
// Confirmation dialog box. Works on all desktop browsers and iPhone.
if (confirm("Are you sure you wish to remove this Targeting?")) {
var num = $('.clonedTargeting').length;
// how many "duplicatable" input fields we currently have
$('#entryTargeting' + num).slideUp('slow', function () {
$(this).remove();
// if only one element remains, disable the "remove" button
if (num - 1 === 1)
$('#TargetingDel').attr('disabled', true);
// enable the "add" button
$('#TargetingAdd').attr('disabled', false).prop('value', "add section");
});
}
return false; // Removes the last section you added
});
});
// Enable the "add" button
$('#TargetingAdd').attr('disabled', false);
// Disable the "remove" button
$('#TargetingDel').attr('disabled', true);
});
;(function($, window, document, undefined) {
"use strict";
$.fn.chained = function(parent_selector, options) {
return this.each(function() {
/* Save this to child because this changes when scope changes. */
var child = this;
var backup = $(child).clone();
/* Handles maximum two parents now. */
$(parent_selector).each(function() {
$(this).bind("change", function() {
updateChildren();
});
/* Force IE to see something selected on first page load, */
/* unless something is already selected */
if (!$("option:selected", this).length) {
$("option", this).first().attr("selected", "selected");
}
/* Force updating the children. */
updateChildren();
});
function updateChildren() {
var trigger_change = true;
var currently_selected_value = $("option:selected", child).val();
$(child).html(backup.html());
/* If multiple parents build classname like foo\bar. */
var selected = "";
$(parent_selector).each(function() {
var selectedClass = $("option:selected", this).val();
if (selectedClass) {
if (selected.length > 0) {
if (window.Zepto) {
/* Zepto class regexp dies with classes like foo\bar. */
selected += "\\\\";
} else {
selected += "\\";
}
}
selected += selectedClass;
}
});
/* Also check for first parent without subclassing. */
/* TODO: This should be dynamic and check for each parent */
/* without subclassing. */
var first;
if ($.isArray(parent_selector)) {
first = $(parent_selector[0]).first();
} else {
first = $(parent_selector).first();
}
var selected_first = $("option:selected", first).val();
$("option", child).each(function() {
/* Remove unneeded items but save the default value. */
if ($(this).hasClass(selected) && $(this).val() === currently_selected_value) {
$(this).prop("selected", true);
trigger_change = false;
} else if (!$(this).hasClass(selected) && !$(this).hasClass(selected_first) && $(this).val() !== "") {
$(this).remove();
}
});
/* If we have only the default value disable select. */
if (1 === $("option", child).size() && $(child).val() === "") {
$(child).prop("disabled", true);
} else {
$(child).prop("disabled", false);
}
if (trigger_change) {
$(child).trigger("change");
}
}
});
};
/* Alias for those who like to use more English like syntax. */
$.fn.chainedTo = $.fn.chained;
/* Default settings for plugin. */
$.fn.chained.defaults = {};
})(window.jQuery || window.Zepto, window, document);
$(document).ready(function(){
$("#connectionSub").chained("#connectionType");
$("#apppagesoptions").chained("#connectionSub");
$("#phoneVersion").chained("#phoneBrand");
$("#osVersionMin").chained("#phoneVersion");
$("#osVersionMax").chained("#phoneVersion");
});
and the HTML is 3 chained inputs:
<div class="Targeting">
<select id="connectionType" name="connectionType[]">
<option disabled value="">--</option>
<option value="pages">Facebook Pages</option>
<option value="apps">Apps</option>
<option disabled value="">--</option>
<option value="advanced">Advanced Connections</option>
</select>
<select id="connectionSub" name="connectionSub[]">
<option value="">--</option>
<option value="page_like" class="pages">People who like your Page</option>
<option value="page_friend" class="pages">Friends of people who like your Page</option>
<option value="page_exclude" class="pages">Exclude people who like your Page</option>
<option value="app_like" class="apps">People who like your App</option>
<option value="app_friend" class="apps">Friends of people who like your App</option>
<option value="app_exclude" class="apps">Exclude people who like your App</option>
</select>
<select id="apppagesoptions" name="apppagesoptions[]" multiple>
<option>test</option>
</select>
</div>
</div><!-- end #entry1 -->
<div id="addDelButtons">
<input type="button" id="TargetingAdd" value="add section">
<input type="button" id="TargetingDel" value="remove section above">
</div>
Appreciate any help with this!
For all the <div class="Targeting"> the select element's ids are remain same. that's why it's only working for first one.

Change the drop down option based on the selected option from other combobox

I have 2 drop downs and if I am selecting a particular option from 1st drop down a set of options should appear in the other drop down and if I select other option from 1st drop down Different set of options should appear in 2nd drop down.
I tried making a fiddle but its not working.
function createOption(value) {
el = document.createElement('option');
el.value = value;
el.innerHTML = value;
el.id = value;
document.getElementById('select').appendChild(el);
}
if(document.getElementById('Type').value === "CD"){
document.getElementById('select').innerHTML = '';
createOption('Volvo');
createOption('Saab');
createOption('Fiat');
};
else{
document.getElementById('select').innerHTML = '';
createOption('Wood');
createOption('Brick')
}
http://jsfiddle.net/33tJR/10/
Please help :)
The main problem with your code is that you don't have any event listeners on an actual "onchange" event that will occur on the first dropdown.
Easy solution for your current code would be something like this:
function createOption(value) {
el = document.createElement('option');
el.value = value;
el.innerHTML = value;
el.id = value;
document.getElementById('select').appendChild(el);
}
document.getElementById('Type').addEventListener("change", function(){
if(document.getElementById('Type').value === "CD"){
document.getElementById('select').innerHTML = '';
createOption('Volvo');
createOption('Saab');
createOption('Fiat');
}
else{
document.getElementById('select').innerHTML = '';
createOption('Wood');
createOption('Brick')
}
});

How to remove text selection from selected text which is coming by default on page load?

When we refresh or reload the page, you can see a selected text in middle of circle when you click on below image portion:
Discuss Goals & Concern
Cash Flow Analysis
Tax Analysis...
And so on.
Example: http://ivyfa.advisorproducts.com/financial-planning-process
The selected text is only coming on the first click - when you click again on those image portions you will not see selected text. So I want to remove the selection from the text on the first attempt too.
It's difficult for me to explain this issue. Below is the JS code I am using - I think the issue is in the ChangeText() functionality.
/*----------Text change on click - Our Process page---------------*/
var prev;
var IdAry = ['slide1', 'slide2', 'slide3', 'slide5', 'slide8', 'slide9', 'slide12', 'slide13', 'slide14', 'slide15', 'slide16'];
window.onload = function() {
for (var zxc0 = 0; zxc0 < IdAry.length; zxc0++) {
var el = document.getElementById(IdAry[zxc0]);
if (el) {
setUpHandler(el);
el.onmouseover = function() {
$(this).addClass("hover");
}
el.onmouseout = function() {
$(this).removeClass("hover");
}
}
}
}
function setUpHandler(el) {
/*---------This is used to add selected class on clicked id only and remove class selected from rest---------*/
$("#" + IdAry.join(",#")).click(function() {
$(this).addClass("selected");
$("#graphics .selected").not(this).removeClass("selected");
})
/*---------This will add show hide class to thier spans and vise versa-------*/
$("#" + IdAry.join(",#")).click(
function() {
changeText(this, "hide", "show");
},
function() {
changeText(this, "show", "hide");
})
}
function changeText(obj, cl1, cl2) {
obj.getElementsByTagName('SPAN')[0].className = "hide";
obj.getElementsByTagName('SPAN')[1].className = "show";
if (prev && obj !== prev) {
prev.getElementsByTagName('SPAN')[0].className = "show";
prev.getElementsByTagName('SPAN')[1].className = "hide";
}
prev = obj
}
I only want to remove the selected text from the text in the middle when you click on different-2 image tag.
Image to view selected text:
You should clear text selection once you display your control; you can do this by calling this function (should be fully cross-browser):
function clearSelection() {
if (window.getSelection) window.getSelection().removeAllRanges();
else if (document.selection) document.selection.empty();
}

Categories