Moving multiple JQueryUI sliders in the DOM while keeping functionality & values - javascript

I have a page with a large number of JQueryUI sliders, in div .origin. Each slider has an associated checkbox. If the checkbox is checked, the slider should be moved- with all values intact- to div .favourites. If the checkbox is unchecked, the slider should be moved back to .origin.
Here's a JSFiddle of my attempts so far.
Here's my function to detect the value of the checkbox and make DOM adjustments accordingly:
$('[type="checkbox"]').click(function () {
var check = $(this),
checked = $(check).prop("checked"),
num = $(check).attr("id").split("-")[1],
parent = $("#food-" + num),
parentContent = $(parent).clone(),
slider = "#" + $(parent).find('.slider').attr("id"),
favelist = $(".favourites .content");
alert(checked)
//remove the original
$(parent).remove();
if (checked === true) {
//add to favourites
$(favelist).append(parentContent);
} else {
//add to origin
$(favelist).append(parentContent);
}
//reinitialise slider
loadSlider(slider)
});
A number of things aren't working:
1) First and most significantly, after the slider and it's parent elements have been moved into the .origin div, clicks on the checkbox no longer register. The alert(checked) doesn't fire, and the else statement doesn't run. Why would a checkbox no longer register a click event after being moved in the DOM?
2) Secondly, the moved sliders have the correct value displayed on the highlight div, but the dragger-handles go back to the starting position. How can I re-initialise the slider with the dragger handle in the correct position?
--
UPDATE- JSFIDDLE
OK, first issue is resolved, thanks to the hint provided by Chad, below. I've rewritten the click event into two functions, so that the click event can be re-instantiated after the elements are re-created in the DOM:
//Listen for checkbox to be checked
function checkboxChecked() {
$('[type="checkbox"]').click(function () {
var checkbox = $(this);
moveItem(checkbox);
});
}
//Create/Destroy items when clicked
function moveItem(checkbox) {
var check = $(checkbox),
checked = $(check).prop("checked"),
num = $(check).attr("id").split("-")[1],
parent = $("#food-" + num),
parentContent = $(parent).clone(),
slider = "#" + $(parent).find('.slider').attr("id"),
favelist = $(".favourites .content"),
origin = $(".all .content");
$(parent).remove();
if (checked === true) {
$(favelist).append(parentContent);
} else {
$(origin).append(parentContent);
}
loadSlider(slider);
checkboxChecked();
}
//initialise checkbox move function
checkboxChecked();
Am still trying to solve the mystery of the handle positions being re-set to 0 despite the slider retaining it's value, as shown on the highlighter track.

Related

Modifying Selectize.js library to allow editing of selected options

Using Selectize.js in an Angular 9 application for selecting multiple values. Please see links to my UI at the end
https://selectize.github.io/selectize.js/
https://github.com/selectize/selectize.js
I'm trying enable the user to edit the already selected values by simply clicking on the selected item. Selectize has the concept of Plugins by which "features can be added to Selectize without modifying the main library." I'm making use of this concept to override onMouseDown event, where I'm attempting to make the clicked item editable. I have successfully used this method to override onKeyDown to implement editing of the last selected value by clicking on backspace. Please see code pasted at the bottom. this.onKeyDown = (function() {...
https://github.com/selectize/selectize.js/blob/master/docs/plugins.md
The already selected items are shown as a layer of div elements over the underlying input. To make a selected item editable, I'm removing the selected element div from the DOM, populating the underlying input element with the text from the div. That way that particular item becomes a input from a div and is editable.
There are a few issues im running into:
Its not possible to determine the caret position from the div that was clicked. I am able to get the div text and pre-populate the input element but not put the caret at the right place in input. By default the caret shows at the end and the user can move it around.
Corer cases around when a name is already being edited and the user clicks on another item to edit. The selectize library is giving api to insert selections only at the end of the already selected items. For me to keep deleting the div's and populating the input to mimic the editing effect I need to be able to insert at different positions but the library doesnt seem to have the capability for it.
Trying to see if anyone has worked on something similar or has any suggestions. Thanks in advance!
var Selectize = require('./selectize-standalone');
(function () {
Selectize.define('break_on_backspace_custom_plugin', function(options) {
var self = this;
options.text = options.text || function(option) {
return option[this.settings.labelField];
};
this.onMouseDown = (function() {
var original = self.onMouseDown;
return function(e) {
var index, option;
if (!this.$control_input.val().length && this.$activeItems.length > 0) {
index = this.caretPos - 1;
var toBeEdited = this.$activeItems[0];
var toBeEditedText = toBeEdited.textContent;
var text = toBeEditedText.substring(0, toBeEditedText.length - 1);
var prevEdit = localStorage.getItem("currentEdit");
if (index >= 0 && index < this.items.length) {
if (this.deleteSelection(e)) {
localStorage.setItem("currentEdit", text);
this.setTextboxValue(text);
this.refreshOptions(true);
if (prevEdit && prevEdit !== text) {
this.addItem(prevEdit);
}
}
//e.preventDefault();
//return;
}
}
//e.preventDefault();
return original.apply(this, arguments);
};
})();
this.onKeyDown = (function() {
var original = self.onKeyDown;
return function(e) {
var index, option;
if (e.keyCode === 8 && this.$control_input.val() === '' && !this.$activeItems.length) {
index = this.caretPos - 1;
if (index >= 0 && index < this.items.length) {
option = this.options[this.items[index]];
if (this.deleteSelection(e)) {
//option.value = option.value.substring(0, option.value.length - 1);
this.setTextboxValue(options.text.apply(this, [option]));
this.refreshOptions(true);
}
e.preventDefault();
return;
}
}
return original.apply(this, arguments);
};
})();
});
return Selectize;
})();
Pictures of UI and work in progress
Editing last element by clicking backspace
https://i.stack.imgur.com/wULcT.png
Editing middle element by clicking on it
https://i.stack.imgur.com/U5hxd.png

How to select/Deselect all checkboxes in oracle apex form

I have a page region in Oracle Apex, that contains many checkboxes (apex form).
I want a functionality to add a checkbox at the header of every checkbox item, that will Select/Deselect all the checkbox items underneath.
I am new to Apex development, and need help on this.
Here's a solution that assumes the text above the checkboxes is from the item's label (somehow I don't think that's the case). If needed, I can update the answer to better fit your page when I know more about it.
First, go into each checkbox where you want to add this "toggle" functionality. Scroll down to the CSS Classes attribute and put toggle-cb in the field.
Next, go to the page level attributes and add the following code to the Function and Global Variable Declaration attribute:
function enableToggle() {
var $wrapperDiv = $(this);
var $label = $wrapperDiv.find('.t-Form-label');
var $item = $wrapperDiv.find('.apex-item-checkbox');
var buttonHtml = '<button type="button" class="t-Button t-Button--tiny t-Button--simple">Toggle all</button>';
$label.html($label.text() + ' ' + buttonHtml);
$label.find('button').on('click', function(event) {
var $button = $(this);
var $checkboxes = $item.find('input[type="checkbox"]');
var checkedCount = $checkboxes.filter(function() {
return this.checked === true;
}).length;
var check = checkedCount < $checkboxes.length;
$checkboxes.each(function() {
this.checked = check;
});
event.stopPropagation();
$button.blur();
});
}
Finally, add the following code to the Execute when Page Loads attribute of the page:
$('.toggle-cb').each(enableToggle);
This will add a button to each item's label (provided the checkbox has the toggle-cb class) that does the toggle:
See the following to learn more about the code used above:
https://www.youtube.com/watch?v=Pjur4Zkkwsk&list=PLUo-NIMouZ_sgdQpMbXXwhHKpwRggCY34&index=1

Event listener fails to attach or remove in some contexts

I've created a script that attaches an event listener to a collection of pictures by default. When the elements are clicked, the listener swaps out for another event that changes the image source and pushes the id of the element to an array, and that reverses if you click on the swapped image (the source changes back and the last element in the array is removed). There is a button to "clear" all of the images by setting the default source and resetting the event listener, but it doesn't fire reliably and sometimes fires with a delay, causing only the last element in a series to be collected.
TL;DR: An event fires very unreliably for no discernible reason, and I'd love to know why this is happening and how I should fix it. The JSFiddle and published version are available below.
I've uploaded the current version here, and you can trip the error by selecting multiple tables, pressing "Cancel", and selecting those buttons again. Normally the error starts on the second or third pass.
I've also got a fiddle.
The layout will be a bit wacky on desktops and laptops since it was designed for phone screens, but you'll be able to see the issue and inspect the code so that shouldn't be a problem.
Code blocks:
Unset all the selected tables:
function tableClear() {
//alert(document.getElementsByClassName('eatPlace')[tableResEnum].src);
//numResTables = document.getElementsByClassName('eatPlace').src.length;
tableArrayLength = tableArray.length - 1;
for (tableResEnum = 0; tableResEnum <= tableArrayLength; tableResEnum += 1) {
tableSrces = tableArray[tableResEnum].src;
//alert(tableSrcTapped);
if (tableSrces === tableSrcTapped) {
tableArray[tableResEnum].removeEventListener('click', tableUntap);
tableArray[tableResEnum].addEventListener('click', tableTap);
tableArray[tableResEnum].src = window.location + 'resources/tableBase.svg';
} /*else if () {
}*/
}
resTableArray.splice(0, resTableArray.length);
}
Set/Unset a particular table:
tableUntap = function () {
$(this).unbind('click', tableUntap);
$(this).bind('click', tableTap);
this.setAttribute('src', 'resources/tableBase.svg');
resTableArray.shift(this);
};
tableTap = function () {
$(this).unbind('click', tableTap);
$(this).bind('click', tableUntap);
this.setAttribute('src', 'resources/tableTapped.svg');
resTableArray.push($(this).attr('id'));
};
Convert the elements within the 'eatPlace' class to an array:
$('.eatPlace').bind('click', tableTap);
tableList = document.getElementsByClassName('eatPlace');
tableArray = Array.prototype.slice.call(tableList);
Table instantiation:
for (tableEnum = 1; tableEnum <= tableNum; tableEnum += 1) {
tableImg = document.createElement('IMG');
tableImg.setAttribute('src', 'resources/tableBase.svg');
tableImg.setAttribute('id', 'table' + tableEnum);
tableImg.setAttribute('class', 'eatPlace');
tableImg.setAttribute('width', '15%');
tableImg.setAttribute('height', '15%');
$('#tableBox').append(tableImg, tableEnum);
if (tableEnum % 4 === 0) {
$('#tableBox').append("\n");
}
if (tableEnum === tableNum) {
$('#tableBox').append("<div id='subbles' class='ajaxButton'>Next</div>");
$('#tableBox').append("<div id='cazzles' class='ajaxButton'>Cancel</div>");
}
}
First mistake is in tapping and untapping tables.
When you push a Table to your array, your pushing its ID.
resTableArray.push($(this).attr('id'));
It will add id's of elements, depending on the order of user clicking the tables.
While untapping its always removing the first table.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift
resTableArray.shift(this);
So, when user clicks tables 1, 2, 3. And unclicks 3, the shift will remove table 1.
Lets fix this by removing untapped table
tableUntap = function () {
$(this).unbind('click', tableUntap);
$(this).bind('click', tableTap);
this.setAttribute('src', 'http://imgur.com/a7J8OJ5.png');
var elementID = $(this).attr('id');
var elementIndex = resTableArray.indexOf(elementID);
resTableArray.splice(elementIndex, 1);
};
So you were missing some tables after untapping.
Well lets fix tableClear,
You have a array with tapped tables, but you are searching in main array.
function tableClear() {
tableLen = resTableArray.length;
for (var i = 0; i < tableLen; i++) {
var idString = "#" + resTableArray[i];
var $element = $(idString);
$element.unbind('click', tableUntap);
$element.bind('click', tableTap);
$element.attr("src", 'http://imgur.com/a7J8OJ5.png');
}
resTableArray = [];
}
Im searching only tapped tables, and then just untap them and remove handlers.
fiddle: http://jsfiddle.net/r9ewnxzs/
Your mistake was to wrongly remove at untapping elements.

Why isn't my div swap working?

So, I need a div to slide up when another slides down.
Example:
When Home button is clicked a div, we'll call it box_Home, slides down. When Games button is clicked, box_Home should slide up and then box_Games should slide down. What's happening is that they are overlapping instead of swapping out.
http://jsfiddle.net/M8UgQ/15/
var open = $('.open'),
a = $('ul').find('a');
console.log(a.hasClass('active'));
open.click(function(e) {
e.preventDefault();
var $this = $(this),
speed = 500;
var link_id = $this.attr('id');
var box_id = '#box_' + link_id;
console.log(box_id);
if($this.hasClass('active') === true) {
$this.removeClass('active');
$(box_id).slideUp(speed);
} else if(a.hasClass('active') === false) {
$this.addClass('active');
$(box_id).slideDown(speed);
} else {
a.removeClass('active')
$(box_id).slideUp(speed);
$this.addClass('active');
$(box_id).delay(speed).slideDown(speed);
}
});
take a look at this
http://jsfiddle.net/rWrJ9/1/
the main idea is...
if the element clicked is active, remove it, otherwise: 1. find (if any) already active elements (using $('.active')) and use jQuery.map() to make them inactive and slide them up, and 2. make the element clicked active.
I also removed the unneeded variable a
IMPORTANT: the this inside the map() function is different from the this (or rather, $this as you called it) outside the map() function
I think you're saying you have two buttons id="Home" class="open" and id="Game" class="open", and two divs id="box_Home" and id="box_Game". If so, you add class="box" to box_Home and box_Game and do something like this:
$('.open').click(function(e) {
e.preventDefault();
var $this = $(this);
var link_id = $this.attr('id');
var box_id = '#box_' + link_id;
$('.box').slideUp();
$(box_id).slideDown();
});
Hi check this fiddle i hope you need thing to implement
jsfiddle
in the if else statement you are doing a mistake
else if(a.hasClass('active') === false) {
replace it with
else if($this.hasClass('active') === false) {

Error message not showing and hiding depending on if else statement

I have a function that loops through all of the inputs of my form and checks if they are filled or not. If the field is blank, it makes that specific input pink and returns false.
I'm trying to add a "Field Required" message underneath the inputs that are not filled. So i coded an extra table row after each one, with a div that holds the error message. The css for the div is set to "display:none" on page load.
Right now my function is showing "required" for every input and not just the ones that are blank, but the pink coloring is still working correctly.
How do I get the "required" div to show and hide correctly like the pink coloring does?
checkinputs = function (blockOne,blockTwo) {
inputGood = true;
blOne = $(blockOne);
blTwo = $(blockTwo);
blInput = [blOne,blTwo];
for (x = 0; x < 2; x++) {
var validators = blInput[x].find(" [id$='RequiredIndicator']").parent().parent('tr').find(':input:not(:hidden)');
var notAllFilled = validators.filter(function(){
var myInput = $(this); //.parent().parent('tr').find(':input');
var filledVal = myInput.val();
var isFilled = $.trim(filledVal).length;
if (isFilled) {
$(this).css('background-color', 'white');
$(this).closest('div').find('.required').hide();
$(this).parent('td').prev('td').find('span').text('*');
}
else {
$(this).css('background-color', 'pink');
$(this).closest('div').find('.required').show();
$(this).parent('td').prev('td').find('span').text('*');
inputGood = false;
}
return isFilled;
}).length;
var inputCount = validators.length;
};
if( !inputGood ){
$('#errorAlert').append('<span style="font-weight:bold;">"Some required information is missing. Please complete the missing fields below."</span>' + '<br><br>');
$('#errorAlertTwo').append('<span style="font-weight:bold;">"Some required credit card information is missing. Please complete the missing fields below."</span>' + '<br><br>');
}
return inputGood;
};
HERE IS A FIDDLE OF THE ISSUE:
http://jsfiddle.net/RNMM7/
Your issue is almost definitely your line to show the div:
$(this).closest('div').find('.required').show();
What this line does is:
Starting at your $(this), it finds the nearest ancestor [including $(this)] that is a div, going up the DOM tree
Finds all elements with class 'required' under that div, and shows them.
Without seeing how your HTML is structured, my guess is that the nearest div element up the DOM tree encompasses all your .required elements. You'd need to replace the 'div' in that statement with an element lower in the DOM tree that would only encompass your $(this) and the one .required element you want to show.

Categories