I've got a weird bug happening on a music library site that I'm working on. The intended functionality (take a form of checkboxes, dynamically change them into selectable words that highlight and "check" the associated checkbox on click, then automatically update the songs below based on the highlighted tags) works fine -- but when you click a selected tag to remove it, it does the correct functionality with the data below and the highlight is removed, but all other selected tags are getting "display: none" added to them.
Here, I think, is the function causing the weird issue:
// Given an label "$label," if it hasn't been selected, then
// highlight the label area and set the "checked" value of the
// appropriate checkbox input to true; if it is already selected,
// remove the highlight and set the "checked" value of the appropriate
// checkbox to "false"
function highlightAndCheck( $label )
{
var id = $label.attr("id"),
$checkbox = $label.prev(),
val = $checkbox.attr("value");
if( id === val )
{
if( $label.hasClass("clicked") )
{
$checkbox.prop("checked", false);
$label.removeClass("clicked");
} else
{
$checkbox.prop("checked", true);
$label.addClass("clicked");
}
}
}
Here's the full jQuery code for the page. I can provide more code if anything is confusing, but I hope the labeling, etc. are straightforward:
$(function() { //on document ready
var $categoriesAndTags = $("div#categories-and-tags"),
$tagCategory = $categoriesAndTags.find("div.tag-category"),
$searchButton = $categoriesAndTags.find("input#public-user-tag-search-submit");
// First, hide the checkboxes and search button, since we don't need them in the dynamic version
$tagCategory.addClass("tag-spinner-skin")
.find("input[type=checkbox]").hide();
$tagCategory.find("br").hide();
$searchButton.hide();
// Make it so then clicking on the text of a tag makes the hidden select box "select"
$tagCategory.find("label").each(function(){
$(this).on("click",function(){
var $this = $(this);
highlightAndCheck( $this );
searchByTags();
//While the unwanted "display:none" bug is happening, use this to make them re-appear on next click
$this.siblings("label").show();
});
});
// Make the search update automatically when a select box is clicked or unclicked.
var tagIDs = getUrlVarValArray( "tagID" );
$tagCategory.find("label").each(function(){
var $this = $(this),
id = $this.attr("id");
if( tagIDs.indexOf( id ) > -1 )
{ highlightAndCheck( $this ); }
});
});
function searchByTags( tags )
{
data = $("form#tag-select input").serialize()
if( data.length > 0 )
{
data += "&search=search";
}
$.ajax({
url: "songs/",
data: data,
type: "GET",
success: function(data){
// DO THIS if we successfully do the Ajax call
$newSongPlayers = $(data).find("div#songs-area");
$("div#songs-area").replaceWith( $newSongPlayers );
$.getScript("javascripts/public.js");
}
});
}
// Given an label "$label," if it hasn't been selected, then
// highlight the label area and set the "checked" value of the
// appropriate checkbox input to true; if it is already selected,
// remove the highlight and set the "checked" value of the appropriate
// checkbox to "false"
function highlightAndCheck( $label )
{
var id = $label.attr("id"),
$checkbox = $label.prev(),
val = $checkbox.attr("value");
if( id === val )
{
if( $label.hasClass("clicked") )
{
$checkbox.prop("checked", false);
$label.removeClass("clicked");
} else
{
$checkbox.prop("checked", true);
$label.addClass("clicked");
}
}
}
function getUrlVarValArray( needle )
{
var results = [],
hash,
hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
for(var i = 0; i < hashes.length; i++)
{
hash = hashes[i].split('=');
if( needle.length > 0 )
{
if( hash[0] === needle )
{
results[ results.length ] = hash[1]; // array[ array.length ] is a faster way to apend than array.push() in small arrays
}
}
}
return results;
}
Thanks in advance for your help! If it's helpful to login and see this in context, please go to the test site and use username: stackoverflowuser; password: HelpMeFigureThisOut -- once you're logged in, click on "View Songs"and the jQuery is referencing the tags at the top of the page.
Look at the following code in the public.js file:
$("html").on("click", function(event){
if(!$(event.target).is('.options-button')
&& !$(event.target).is('input.add-new-playlist')
&& !$(event.target).is('button.submit-new-playlist')
&& !$(event.target).is('button.add-song-to-playlist')
&& !$(event.target).is('button.playlist-popup-button')
)
{
if(!$(event.target).is('.clicked') && !$(event.target).is('.clicked > div') )
{ $(".clicked").hide().removeClass("clicked"); }
}
});
This handler gets executed because the click event propagates from the <label> element to the <html> element. It executes after the click handler on the <label> element, which removes the "clicked" class from the <label> element. Since the <label> element is the event.target and no longer has the "clicked" class, the following line is executed:
$(".clicked").hide().removeClass("clicked");
That line hides all the labels that still have the "clicked" class.
Related
So I have a button that whenever clicked appends whatever the user entered below the input field. I want to make it so when clicked with an empty field nothing appends (essentially the function does not run).
Here is my code:
var ingrCount = 0
$("#addIngrButton").on('click', function() {
var ingredientInput = $("#ingredients").val().trim();
var ingredientSpace = $("<p>");
ingredientSpace.attr("id", "ingredient-" + ingrCount);
ingredientSpace.append(" " + ingredientInput);
var ingrClose = $("<button>");
ingrClose.attr("data-ingr", ingrCount);
ingrClose.addClass("deleteBox");
ingrClose.append("✖︎");
// Append the button to the to do item
ingredientSpace = ingredientSpace.prepend(ingrClose);
// Add the button and ingredient to the div
$("#listOfIngr").append(ingredientSpace);
// Clear the textbox when done
$("#ingredients").val("");
// Add to the ingredient list
ingrCount++;
if (ingredientInput === "") {
}
});
So I wanted to create an if statement saying when the input is blank then the function does not run. I think I may need to move that out of the on click function though. For the if statement I added a disabled attribute and then removed it when the input box contains something. But that turns the button another color and is not the functionality I want. Any ideas I can test out would help. If you need any more information please ask.
If you're testing if ingredientInput is empty, can you just return from within the click event?
$("#addIngrButton").on('click', function() {
var ingredientInput = $("#ingredients").val().trim();
if(ingredientInput === '') { return; }
// rest of code
Simply use :
$("#addIngrButton").on('click', function() {
var ingredientInput = $("#ingredients").val().trim();
if (ingredientInput.length == 0) {
return false;
}
// ..... your code
I have a form with three select options:
Fit
Colour
Size
By default, the 'Fit' dropdown and 'Colour' dropdown are active with a default value selected (e.g. Regular Fit and Blue Colour).
There are three different 'Size' dropdowns, but only one is visible at any time depending on what is selected from the 'Fit' dropdown.
The Button is disabled if an option value="none".
Problem
The Button only becomes active if all three 'Size' dropdowns are altered so that their value is not "none" (this is done by selecting an initial size for Regular, and then selecting Petite and Long from the 'Fit' dropdown). Ideally, I only want the button to take into account the 'Size' dropdown that is active.
Update
Working jsFiddle solution provided by #nagappan below, big thanks.
https://jsfiddle.net/dodgers76/c0dvdwbz/
var currentSelectedVals = {'selector-fit':'','selector-color':'','selector-sizes':''};
var disableComboVals = [
{'selector-fit':'','selector-color':'','selector-sizes':'none'},
{'selector-fit':'petite','selector-color':'','selector-sizes':'10'},
{'selector-fit':'petite','selector-color':'','selector-sizes':'20'},
{'selector-fit':'petite','selector-color':'','selector-sizes':'22'},
{'selector-fit':'petite','selector-color':'','selector-sizes':'24'},
{'selector-fit':'long','selector-color':'','selector-sizes':'22'},
{'selector-fit':'long','selector-color':'','selector-sizes':'24'}
];
function checkDisableCombo() {
return $.grep(disableComboVals, function(vals){
cnt = 0;
$.each(vals, function(key,val) {
console.log('comparing key val '+key+val);
if (val === '' || val === currentSelectedVals[key]) {
console.log('>>matched values');
cnt = cnt + 1;
}
});
if (cnt===3) {
return true;
}
return false;
});
};
$(function(){
var sizeVal = 'none';
$("select.selector-fit").on("change", function(){
//remove active
$("select.selector-sizes.active").removeClass("active");
//check if select class exists. If it does then show it
var subList = $("select.selector-sizes."+$(this).val());
if (subList.length){
//class exists. Show it by adding active class to it
subList.addClass("active");
subList.val(sizeVal);
}
});
$('.selector-sizes').on('change', function() {
sizeVal = $(this).val();
});
});
$(function() {
$('.selector').on('change', function() {
var $sels = $('option.selector-sizes:selected[value="none"]');
var isSizeSelector = jQuery.inArray( "selector-sizes",this.classList);
currentSelectedVals[this.classList[1]] = this.value;
console.log(currentSelectedVals);
var result = checkDisableCombo();
console.log(result);
if ( result.length > 0) {
console.log('disabled false');
$("#Testing").attr("disabled", true);
} else {
$("#Testing").attr("disabled", false);
}
}).change();
});
If we want to disable the button by combination of the drop down selected values. We can have a global variable to track the current selected values from three drop downs. Only we can have array of disbale combos. So whenever user select a value we cross check with disable combos and if it matches we can disable the button. Validate the combo can be done as below. Updated the jsfiddle link. JS FIDDLE UPDATED
function checkDisableCombo() {
return $.grep(disableComboVals, function(vals){
cnt = 0;
$.each(vals, function(key,val) {
console.log('comparing key val '+key+val);
if (val === '' || val === currentSelectedVals[key]) {
console.log('>>matched values');
cnt = cnt + 1;
}
});
if (cnt===3) {
return true;
}
return false;
});
Here is a live demo: jsfiddle
The filtering is working great for the box on the left.
The moving items between the two lists also works great.
The problem occurs when I move an item into the right box, then filter, it removes everything from the right box.
How can I have it leave items in the right box upon filtering and not have those items show up in the left box if they are in the right box (to avoid duplicates)?
//MOVE SPECS BETWEEN BOXES
function moveListItems(sourceID, destinationID) {
var whatToMove = $("#"+sourceID+" option:selected");
if ( sourceID = "excluded-select" ) {
whatToMove.attr('class', 'included-option');
}
if ( sourceID = "included-select" ) {
whatToMove.attr('class', 'excluded-option');
}
whatToMove.remove().appendTo("#"+destinationID);
return false;
}
$("#move-right-btn").click(function(){
moveListItems("excluded-select", "included-select");
return false;
});
$("#move-left-btn").click(function(){
moveListItems("included-select", "excluded-select");
return false;
});
var $opts = $(".excluded-option");
$("#filter-specs-text").keyup(function () {
var searchString = $(this).val().toLowerCase();
$("#excluded-select").empty().append($opts);
$(".excluded-option").each(function () {
var text = $(this).text().toLowerCase();
//found a match - show this entry
if (text.indexOf(searchString) > -1) {
$(this).prop("disabled", false);
}
//no match - hide this entry
else {
$(this).prop("disabled", true).detach();
}
});
});
The problem is the $opts always contains all the .excluded-options, in the onkeyup handler you write, it appends all $opts to the first select and filter the list then, that's why the included options (which should be kept in the second select) are pushed back to the first. To solve this you have to update the $opts each time you move the items between the 2 selects:
$("#filter-specs-text").keyup(function () {
//...
//Use $opts here instead of $('.excluded-option')
$opts.each(function () {
//...
}
}
function moveListItems(sourceID, destinationID) {
var whatToMove = $("#"+sourceID+" option:selected");
//here you update the $opts accordingly...
if(sourceID == "excluded-select") $opts = $opts.not(whatToMove);
else $opts = $opts.add(whatToMove);
whatToMove.remove().appendTo("#"+destinationID);
return false;
}
Note that you should update the $opts instead of re-select the .excluded-option everytime the keyup is triggered, it's so terrible to do it that way.
Demo.
Since you are selecting $opts upfront, those items selected will stay the same even though you change their class or id. You have to reselect them on your keyup event handler.
On my current project we have some modal panes that open up on certain actions. I am trying to get it so that when that modal pane is open you can't tab to an element outside of it. The jQuery UI dialog boxes and the Malsup jQuery block plugins seem to do this but I am trying to get just that one feature and apply it in my project and it's not immediately obvious to me how they are doing that.
I've seen that some people are of the opinion that tabbing shouldn't be disabled and I can see that point of view but I am being given the directive to disable it.
This is just expanding on Christian answer, by adding the additional input types and also taking into consideration the shift+tab.
var inputs = $element.find('select, input, textarea, button, a').filter(':visible');
var firstInput = inputs.first();
var lastInput = inputs.last();
/*set focus on first input*/
firstInput.focus();
/*redirect last tab to first input*/
lastInput.on('keydown', function (e) {
if ((e.which === 9 && !e.shiftKey)) {
e.preventDefault();
firstInput.focus();
}
});
/*redirect first shift+tab to last input*/
firstInput.on('keydown', function (e) {
if ((e.which === 9 && e.shiftKey)) {
e.preventDefault();
lastInput.focus();
}
});
I was finally able to accomplish this at least somewhat by giving focus to the first form element within the modal pane when that modal pane is open and then if the Tab key is pressed while focus is on the last form element within the modal pane then the focus goes back to the first form element there rather than to the next element in the DOM that would otherwise receive focus. A lot of this scripting comes from jQuery: How to capture the TAB keypress within a Textbox:
$('#confirmCopy :input:first').focus();
$('#confirmCopy :input:last').on('keydown', function (e) {
if ($("this:focus") && (e.which == 9)) {
e.preventDefault();
$('#confirmCopy :input:first').focus();
}
});
I may need to further refine this to check for the pressing of some other keys, such as arrow keys, but the basic idea is there.
Good solutions by Christian and jfutch.
Its worth mentioning that there a few pitfalls with hijacking the tab keystroke:
the tabindex attribute might be set on some elements inside the modal pane in such a way that the dom order of elements does not follow the tab order. (Eg. setting tabindex="10" on the last tabbable element can make it first in the tab order)
If the user interacts with an element outside the modal that doesn't trigger the modal to close you can tab outside the modal window. (Eg. click the location bar and start tabbing back to the page, or open up page landmarks in a screenreader like VoiceOver & navigate to a different part of the page)
checking if elements are :visible will trigger a reflow if the dom is dirty
The document might not have a :focussed element. In chrome its possible to change the 'caret' position by clicking on a non-focussable element then pressing tab. Its possible that the user could set the caret position past the last tabbable element.
I think a more robust solution would be to 'hide' the rest of the page by setting tabindex to -1 on all tabbable content, then 'unhide' on close. This will keep the tab order inside the modal window and respect the order set by tabindex.
var focusable_selector = 'a[href], area[href], input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]';
var hide_rest_of_dom = function( modal_selector ) {
var hide = [], hide_i, tabindex,
focusable = document.querySelectorAll( focusable_selector ),
focusable_i = focusable.length,
modal = document.querySelector( modal_selector ),
modal_focusable = modal.querySelectorAll( focusable_selector );
/*convert to array so we can use indexOf method*/
modal_focusable = Array.prototype.slice.call( modal_focusable );
/*push the container on to the array*/
modal_focusable.push( modal );
/*separate get attribute methods from set attribute methods*/
while( focusable_i-- ) {
/*dont hide if element is inside the modal*/
if ( modal_focusable.indexOf(focusable[focusable_i]) !== -1 ) {
continue;
}
/*add to hide array if tabindex is not negative*/
tabindex = parseInt(focusable[focusable_i].getAttribute('tabindex'));
if ( isNaN( tabindex ) ) {
hide.push([focusable[focusable_i],'inline']);
} else if ( tabindex >= 0 ) {
hide.push([focusable[focusable_i],tabindex]);
}
}
/*hide the dom elements*/
hide_i = hide.length;
while( hide_i-- ) {
hide[hide_i][0].setAttribute('data-tabindex',hide[hide_i][1]);
hide[hide_i][0].setAttribute('tabindex',-1);
}
};
To unhide the dom you would just query all elements with the 'data-tabindex' attribute &
set the tabindex to the attribute value.
var unhide_dom = function() {
var unhide = [], unhide_i, data_tabindex,
hidden = document.querySelectorAll('[data-tabindex]'),
hidden_i = hidden.length;
/*separate the get and set attribute methods*/
while( hidden_i-- ) {
data_tabindex = hidden[hidden_i].getAttribute('data-tabindex');
if ( data_tabindex !== null ) {
unhide.push([hidden[hidden_i], (data_tabindex == 'inline') ? 0 : data_tabindex]);
}
}
/*unhide the dom elements*/
unhide_i = unhide.length;
while( unhide_i-- ) {
unhide[unhide_i][0].removeAttribute('data-tabindex');
unhide[unhide_i][0].setAttribute('tabindex', unhide[unhide_i][1] );
}
}
Making the rest of the dom hidden from aria when the modal is open is slightly easier. Cycle through all the
relatives of the modal window & set the aria-hidden attribute to true.
var aria_hide_rest_of_dom = function( modal_selector ) {
var aria_hide = [],
aria_hide_i,
modal_relatives = [],
modal_ancestors = [],
modal_relatives_i,
ancestor_el,
sibling, hidden,
modal = document.querySelector( modal_selector );
/*get and separate the ancestors from the relatives of the modal*/
ancestor_el = modal;
while ( ancestor_el.nodeType === 1 ) {
modal_ancestors.push( ancestor_el );
sibling = ancestor_el.parentNode.firstChild;
for ( ; sibling ; sibling = sibling.nextSibling ) {
if ( sibling.nodeType === 1 && sibling !== ancestor_el ) {
modal_relatives.push( sibling );
}
}
ancestor_el = ancestor_el.parentNode;
}
/*filter out relatives that aren't already hidden*/
modal_relatives_i = modal_relatives.length;
while( modal_relatives_i-- ) {
hidden = modal_relatives[modal_relatives_i].getAttribute('aria-hidden');
if ( hidden === null || hidden === 'false' ) {
aria_hide.push([modal_relatives[modal_relatives_i]]);
}
}
/*hide the dom elements*/
aria_hide_i = aria_hide.length;
while( aria_hide_i-- ) {
aria_hide[aria_hide_i][0].setAttribute('data-ariahidden','false');
aria_hide[aria_hide_i][0].setAttribute('aria-hidden','true');
}
};
Use a similar technique to unhide the aria dom elements when the modal closes. Here its better
to remove the aria-hidden attribute rather than setting it to false as there might be some conflicting
css visibility/display rules on the element that take precedence & implementation of aria-hidden
in such cases is inconsistent across browsers (see https://www.w3.org/TR/2016/WD-wai-aria-1.1-20160721/#aria-hidden)
var aria_unhide_dom = function() {
var unhide = [], unhide_i, data_ariahidden,
hidden = document.querySelectorAll('[data-ariahidden]'),
hidden_i = hidden.length;
/*separate the get and set attribute methods*/
while( hidden_i-- ) {
data_ariahidden = hidden[hidden_i].getAttribute('data-ariahidden');
if ( data_ariahidden !== null ) {
unhide.push(hidden[hidden_i]);
}
}
/*unhide the dom elements*/
unhide_i = unhide.length;
while( unhide_i-- ) {
unhide[unhide_i].removeAttribute('data-ariahidden');
unhide[unhide_i].removeAttribute('aria-hidden');
}
}
Lastly I'd recommend calling these functions after an animation has ended on the element. Below is a
abstracted example of calling the functions on transition_end.
I'm using modernizr to detect the transition duration on load. The transition_end event bubbles up
the dom so it can fire more than once if more than one element is transitioning when the modal
window opens, so check against the event.target before calling the hide dom functions.
/* this can be run on page load, abstracted from
* http://dbushell.com/2012/12/22/a-responsive-off-canvas-menu-with-css-transforms-and-transitions/
*/
var transition_prop = Modernizr.prefixed('transition'),
transition_end = (function() {
var props = {
'WebkitTransition' : 'webkitTransitionEnd',
'MozTransition' : 'transitionend',
'OTransition' : 'oTransitionEnd otransitionend',
'msTransition' : 'MSTransitionEnd',
'transition' : 'transitionend'
};
return props.hasOwnProperty(transition_prop) ? props[transition_prop] : false;
})();
/*i use something similar to this when the modal window is opened*/
var on_open_modal_window = function( modal_selector ) {
var modal = document.querySelector( modal_selector ),
duration = (transition_end && transition_prop) ? parseFloat(window.getComputedStyle(modal, '')[transition_prop + 'Duration']) : 0;
if ( duration > 0 ) {
$( document ).on( transition_end + '.modal-window', function(event) {
/*check if transition_end event is for the modal*/
if ( event && event.target === modal ) {
hide_rest_of_dom();
aria_hide_rest_of_dom();
/*remove event handler by namespace*/
$( document ).off( transition_end + '.modal-window');
}
} );
} else {
hide_rest_of_dom();
aria_hide_rest_of_dom();
}
}
I have just made few changes to Alexander Puchkov's solution, and made it a JQuery plugin. It solves the problem of dynamic DOM changes in the container. If any control add it to the container on conditional, this works.
(function($) {
$.fn.modalTabbing = function() {
var tabbing = function(jqSelector) {
var inputs = $(jqSelector).find('select, input, textarea, button, a[href]').filter(':visible').not(':disabled');
//Focus to first element in the container.
inputs.first().focus();
$(jqSelector).on('keydown', function(e) {
if (e.which === 9) {
var inputs = $(jqSelector).find('select, input, textarea, button, a[href]').filter(':visible').not(':disabled');
/*redirect last tab to first input*/
if (!e.shiftKey) {
if (inputs[inputs.length - 1] === e.target) {
e.preventDefault();
inputs.first().focus();
}
}
/*redirect first shift+tab to last input*/
else {
if (inputs[0] === e.target) {
e.preventDefault();
inputs.last().focus();
}
}
}
});
};
return this.each(function() {
tabbing(this);
});
};
})(jQuery);
For anyone coming into this more recently like I was, I've taken the approaches outlined above and I've simplified them a bit to make it a bit more digestible. Thanks to #niall.campbell for the suggested approach here.
The code below can be found in this CodeSandbox for further reference and for a working example
let tabData = [];
const modal = document.getElementById('modal');
preventTabOutside(modal);
// should be called when modal opens
function preventTabOutside(modal) {
const tabbableElements = document.querySelectorAll(selector);
tabData = Array.from(tabbableElements)
// filter out any elements within the modal
.filter((elem) => !modal.contains(elem))
// store refs to the element and its original tabindex
.map((elem) => {
// capture original tab index, if it exists
const tabIndex = elem.hasAttribute("tabindex")
? elem.getAttribute("tabindex")
: null;
// temporarily set the tabindex to -1
elem.setAttribute("tabindex", -1);
return { elem, tabIndex };
});
}
// should be called when modal closes
function enableTabOutside() {
tabData.forEach(({ elem, tabIndex }) => {
if (tabIndex === null) {
elem.removeAttribute("tabindex");
} else {
elem.setAttribute("tabindex", tabIndex);
}
});
tabData = [];
}
I've got a form that uses jqTransform to replace the standard select boxes and radio buttons. It all works fine and dandy, except one thing that annoys me:
Since it replaces the select box with a list of links, when you type a letter to scroll it doesn't do anything. For instance, you click to open up the select, then type an S. It should scroll to the first S in the list, but nothing happens. Is there a way to re-instate this functionality? Below is the jqTransform code for the select box. I don't see a handler for this type of thing:
/***************************
Select
***************************/
$.fn.jqTransSelect = function(){
return this.each(function(index){
var $select = $(this);
if($select.hasClass('jqTransformHidden')) {return;}
if($select.attr('multiple')) {return;}
var oLabel = jqTransformGetLabel($select);
/* First thing we do is Wrap it */
var $wrapper = $select
.addClass('jqTransformHidden')
.wrap('<div class="jqTransformSelectWrapper"></div>')
.parent()
.css({zIndex: 10-index})
;
/* Now add the html for the select */
$wrapper.prepend('<div><span></span></div><ul></ul>');
var $ul = $('ul', $wrapper).css('width',$select.width()).hide();
/* Now we add the options */
$('option', this).each(function(i){
var oLi = $('<li>'+ $(this).html() +'</li>');
$ul.append(oLi);
});
/* Add click handler to the a */
$ul.find('a').click(function(){
$('a.selected', $wrapper).removeClass('selected');
$(this).addClass('selected');
/* Fire the onchange event */
if ($select[0].selectedIndex != $(this).attr('index') && $select[0].onchange) { $select[0].selectedIndex = $(this).attr('index'); $select[0].onchange(); }
$select[0].selectedIndex = $(this).attr('index');
$('span:eq(0)', $wrapper).html($(this).html());
$ul.hide();
return false;
});
/* Set the default */
$('a:eq('+ this.selectedIndex +')', $ul).click();
$('span:first', $wrapper).click(function(){$("a.jqTransformSelectOpen",$wrapper).trigger('click');});
oLabel && oLabel.click(function(){$("a.jqTransformSelectOpen",$wrapper).trigger('click');});
this.oLabel = oLabel;
/* Apply the click handler to the Open */
var oLinkOpen = $('a.jqTransformSelectOpen', $wrapper)
.click(function(){
//Check if box is already open to still allow toggle, but close all other selects
if( $ul.css('display') == 'none' ) {jqTransformHideSelect();}
if($select.attr('disabled')){return false;}
$ul.slideToggle('fast', function(){
var offSet = ($('a.selected', $ul).offset().top - $ul.offset().top);
$ul.animate({scrollTop: offSet});
});
return false;
})
;
// Set the new width
var iSelectWidth = $select.outerWidth();
var oSpan = $('span:first',$wrapper);
var newWidth = (iSelectWidth > oSpan.innerWidth())?iSelectWidth+oLinkOpen.outerWidth():$wrapper.width();
$wrapper.css('width',newWidth);
$ul.css('width',newWidth-2);
oSpan.css({width:iSelectWidth});
$ul.css({height:'420px','overflow':'hidden'});
// Calculate the height if necessary, less elements that the default height
//show the ul to calculate the block, if ul is not displayed li height value is 0
$ul.css({display:'block',visibility:'hidden'});
var iSelectHeight = ($('li',$ul).length)*($('li:first',$ul).height());//+1 else bug ff
(iSelectHeight < $ul.height()) && $ul.css({height:iSelectHeight,'overflow':'hidden'});//hidden else bug with ff
$ul.css({display:'none',visibility:'visible'});
});
};
Here is what we tried to do to implement this:
var oLinkOpen = $('a.jqTransformSelectOpen', $wrapper)
.keypress(function (e) {
$.each(myArray, function (i, l) {
var sc = l.substr(0, 1).toLowerCase();
var kc = String.fromCharCode(e.which);
if (sc == kc) {
$select[0].selectedIndex = i;
$('span:eq(0)', $wrapper).html(l);
$ul.hide();
return false;
}
});
});
Oh dang. I was missing the big picture without the code. Now I see what's going on... yeah, there's no "reinstating" the functionality since the new list of links is not actually a select box anymore. If jqTransform doesn't include a scrollable option by default I think you'll have to implement one.
If you look at their demo page, their "plain" select box works as expected (although it's hard to notice since all options start with "O", it WILL jump to the first "Option") and their styled select box does not.
Without looking deeper at the code, I suspect that means that a keypress capture is not implemented in the plug-in itself.
I'm afraid this isn't the "answer" you were probably hoping for. With any luck someone who has done this sort of thing before will hear your plea. ;-)
solution for jqTransform select keypress work link visit http://www.techapparatus.com/jqtransform-select-problem-with-keyboard-type-solution
Add the following code at the end of return this.each(function(index){ ... }); that is inside of $.fn.jqTransSelect function.
Also you have to install the scrollTo jquery plugin.
CODE:
var newChar;
$(document).bind("keydown", function (e) {
var char = String.fromCharCode(e.which);
var code = e.keyCode || e.which;
var charFound;
if( $ul.css('display') != 'none' ){
if (newChar != char){
newChar = char;
$ul.find('a').each(function(){
// Find first occurence of li that starts with letter typed
if ($(this).text().substr(0,1).toUpperCase() == char && $(this).text() != "Choose"){
charFound = true;
$('a.selected', $wrapper).removeClass('selected');
$(this).addClass('selected');
$select[0].selectedIndex = $(this).attr('index');
$($select[0]).trigger('change');
$that = $(this);
return false;
}
});
if (charFound == true){
// Scroll to selected value
$ul.scrollTo($('a.selected', $ul), 400);
}
}
//If Enter has been pressed, select the value
if(code == 13) {
$('span:eq(0)', $wrapper).html($that.html());
$ul.hide();
return false;
}
}
});