How to disable jQuery accordion conditionally - javascript

I want to enable and disable or better to add and remove jQuery accordion on my menu conditionally, is it possible to add or remove this on screen rotate or screen-size change ? I tried it but It does not seems to be working, The accordion is remaining for change in screen-size .
jQuery( document ).ready( function(){
apply_accordion();
jQuery(window).on("orientationchange",function(){
apply_accordion();
});
} );
function apply_accordion(){
if (jQuery(window).width() < 540) {
jQuery('.footer-area').accordion({
icons: { "header": "icon-large ui-icon-carat-1-s", "activeHeader": "icon-large ui-icon-caret-1-n" },
active: false,
autoHeight: false,
navigation: true,
collapsible: true,
});
} else {
//jQuery( '.footer-area' ).accordion( "disable" );
//jQuery( '.footer-area' ).accordion( "destroy" );
// jQuery( '.footer-area' ).accordion( "refresh" );
jQuery( '.footer-area' ).accordion( "destroy" ).accordion();
}
}
update
if else part will be,
} else {
jQuery( '.footer-area' ).accordion( "destroy" );
jQuery('.footer-area').accordion('option', 'active', 0);
}
when I starts with moving from portrait to landscape, it is working, but the reverse is not working , means when I am moving from landscape to portrait it is not working . And also gives error in console cannot call methods on accordion prior to initialization; attempted to call method 'destroy'
New jsfield
I would like to remove and add accordion with screen size.
Note:
jQuery version 1.11.4
check Techbreak's answer https://jsfiddle.net/voytfj2q/20/ it seems to be working but if you will check console it will generate " Uncaught Error: cannot call methods on accordion prior to initialization; attempted to call method 'destroy'" . and in actual implementation it does not work when I am moving from landscape to portrait.
And I have also posted an workaround, for now in my implementation it is working for me, but I know this is only a workaround.
Here is another fiddle if you will increase and decrease the screen-size slowly you can notice the issue.
Screenshot of issue, you can notice for few of them the accordion is disabled for increase in size and for some it is not disabled.

You need to activate the accordian to expand when the size is big enough to expand the content or screen rotated completely as follows,
jQuery(document).ready(function() {
jQuery(window).on("resize", function() {
if (jQuery(window).width() < 540) {
jQuery('.footer-area').accordion({
active: false, collapsible:true, active:true
});
} else {
//reactivate the accordian so that it can be expanded again
jQuery('.footer-area').accordion('option', 'active', 0);
}
});
Working fiddle for your example : https://jsfiddle.net/voytfj2q/18/
});

OK. Actually, you have solved the issue with many different instances of the accordion, which wasn't in evidence from your original post, so the wrong selector .footer-area used here:
jQuery('.footer-area').accordion({
active: false, collapsible:true, active:true
});
has been adjusted.
Issue #1:
As you need to create and destroy the widget based on the page size, we need to check for the existence of every widget instance before calling any method of the accordion, otherwise we will raise the infamous error: ...cannot call methods on *some-widget* prior to initialization.
This issue is solved by checking for the existence of the data which has been appended to the element at widget instance creation:
var isInstance1 = (typeof jQuery('#footer-widget-area-1 .footer-area').data("ui-accordion") != "undefined");
Issue #2:
When you are switching back to the unstyled menu, the page height will increase and the page will show the vertical scrollbar, which is resulting in a different page width. The page is resized again and your check for window.width will behave unstable.
This is the reason why you need to check for jQuery('body').width() + scrollbar_width(). Simply take the provided function to get the scrollbar width as-is, and include it in your snippet lbrary.
Fiddle: https://jsfiddle.net/Lgx4es86/6/
/* Calculates scrollbar width in pixels */
function scrollbar_width() {
if( jQuery('body').height() > jQuery(window).height()) {
/* Modified from: http://jdsharp.us/jQuery/minute/calculate-scrollbar-width.php */
var calculation_content = jQuery('<div style="width:50px;height:50px;overflow:hidden;position:absolute;top:-200px;left:-200px;"><div style="height:100px;"></div>');
jQuery('body').append( calculation_content );
var width_one = jQuery('div', calculation_content).innerWidth();
calculation_content.css('overflow-y', 'scroll');
var width_two = jQuery('div', calculation_content).innerWidth();
jQuery(calculation_content).remove();
return ( width_one - width_two );
}
return 0;
}
jQuery( document ).ready( function(){
apply_accordion();
jQuery(window).resize(function() {
apply_accordion();
});
} );
function apply_accordion(){
var ww = jQuery('body').width() + scrollbar_width();
if (ww < 540) {
jQuery('#footer-widget-area-1 .footer-area').accordion({
active: false, collapsible:true
});
jQuery('#footer-widget-area-2 .footer-area').accordion({
active: false, collapsible:true
});
jQuery('#footer-widget-area-3 .footer-area').accordion({
active: false, collapsible:true
});
jQuery('#footer-widget-area-5 .footer-area').accordion({
active: false, collapsible:true
});
jQuery('#footer-widget-area-6 .footer-area').accordion({
active: false, collapsible:true
});
} else {
var isInstance1 = (typeof jQuery('#footer-widget-area-1 .footer-area').data("ui-accordion") != "undefined");
if (isInstance1) {
jQuery('#footer-widget-area-1 .footer-area').accordion('option', 'active', 0);
jQuery('#footer-widget-area-1 .footer-area').accordion("destroy");
}
var isInstance2 = (typeof jQuery('#footer-widget-area-2 .footer-area').data("ui-accordion") != "undefined");
if (isInstance2) {
jQuery('#footer-widget-area-2 .footer-area').accordion('option', 'active', 0);
jQuery('#footer-widget-area-2 .footer-area').accordion("destroy");
}
var isInstance3 = (typeof jQuery('#footer-widget-area-3 .footer-area').data("ui-accordion") != "undefined");
if (isInstance3) {
jQuery('#footer-widget-area-3 .footer-area').accordion('option', 'active', 0);
jQuery('#footer-widget-area-3 .footer-area').accordion("destroy");
}
var isInstance5 = (typeof jQuery('#footer-widget-area-5 .footer-area').data("ui-accordion") != "undefined");
if (isInstance5) {
jQuery('#footer-widget-area-5 .footer-area').accordion('option', 'active', 0);
jQuery('#footer-widget-area-5 .footer-area').accordion("destroy");
}
var isInstance6 = (typeof jQuery('#footer-widget-area-6 .footer-area').data("ui-accordion") != "undefined");
if (isInstance6) {
jQuery('#footer-widget-area-6 .footer-area').accordion('option', 'active', 0);
jQuery('#footer-widget-area-6 .footer-area').accordion("destroy");
}
// var isInstance = (typeof jQuery('.footer-area').data("ui-accordion") != "undefined");
// if (isInstance){
// jQuery('.footer-area').accordion('option', 'active', 0);
// jQuery('.footer-area').accordion( "destroy" );
// }
}
}
Your workaround:
You are applying and removing the accordion styles, but not destroying the widget instances, so data event handlers are still there. You would need at least to move the jQuery('.footer-area').accordion part in another place to execute it just only one time. Moreover, beside this, the page width issue isn't solved by your workaround.
Scrollbar width function: credit Alex Mansfield (http://alexmansfield.com/javascript/css-jquery-screen-widths-scrollbars)

A work around will be removing and adding the classes and attributes when ever the screen size is changing. I am posting this workaround but would like to have an correct solution to it.
jQuery(document).ready(function() {
jQuery(window).on("resize", function() {
if (jQuery(window).width() < 540) {
jQuery('.footer-area').accordion({
active: false, collapsible:true, active:true
});
jQuery('.footer-area h2').append('<span class="ui-accordion-header-icon ui-icon ui-icon-carat-1-s"></span>');
jQuery('.footer-area div').css('display', 'none');
jQuery('.footer-area div').addClass('ui-widget-content');
jQuery('.footer-area div').addClass('ui-accordion-content');
jQuery('.footer-area h2').addClass('ui-accordion-header');
jQuery('.footer-area h2').addClass('ui-accordion-icons');
} else {
jQuery('.footer-area h2 .ui-accordion-header-icon').remove();
jQuery('.footer-area div').removeAttr('style');
jQuery('.footer-area div').removeClass('ui-widget-content');
jQuery('.footer-area div').removeClass('ui-accordion-content');
jQuery('.footer-area h2').removeClass('ui-accordion-header');
jQuery('.footer-area h2').removeClass('ui-accordion-icons');
}
});

There an option using pure css in which you can use media quires to show or hide them accordingly based on screen size:
Let's say you have ui-accordion-header class on your accordion headers when it's rendered.
Now you can put this in your style sheet:
#media screen and (min-width: 0) and (max-width: 1024px) {
.ui-accordion-header { display: block; } /* show it on small screens */
}
#media screen and (min-width: 0) and (max-width: 400px) {
.ui-accordion-header { display: none; } /* hide it elsewhere */
}
Or:
#media all and (orientation:portrait) {
.ui-accordion-header { display: none; }
}
#media all and (orientation:landscape) {
.ui-accordion-header { display: block; }
}
And you don't need to write any js code. Check the code here.

var myAccordion = null;
jQuery(document).ready(function () {
createAccordion(true);
jQuery(window).bind("resize", function (event) {
updateAccordion();
});
});
function createAccordion(value){
try{
$(".footer-area").accordion({
icons: {"header": "icon-large ui-icon-carat-1-s", "activeHeader": "icon-large ui-icon-caret-1-n"},
active: 0,
// heightStyle: "fill",
collapsible: value
});
}catch(e){
alert(e);
}
}
function updateAccordion() {
try{
var w = jQuery(window).width();
if (w < 540){
$(".footer-area").accordion("option", "collapsible", false);
}else{
$(".footer-area").accordion("option", "collapsible", true);
}
}catch(e){
alert(e);
}
}

Related

Cannot use onClick in HTML/CSS template in #header

I am using a HTML/CSS template and cannot use the onClick event inside my header. I have tried it everywhere, if I remove the #header class then it works just fine, so it must be something that is preventing it within the js I assume. I have looked in the js and I removed something called hideOnClick, but that did nothing so far.
I will post the JS below. I am rather poor with jquery and things like that so if it is something obvious I apologize.
/*
Prologue by HTML5 UP
html5up.net | #ajlkn
Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
*/
(function($) {
skel.breakpoints({
wide: '(min-width: 961px) and (max-width: 1880px)',
normal: '(min-width: 961px) and (max-width: 1620px)',
narrow: '(min-width: 961px) and (max-width: 1320px)',
narrower: '(max-width: 960px)',
mobile: '(max-width: 736px)'
});
$(function() {
var $window = $(window),
$body = $('body');
// Disable animations/transitions until the page has loaded.
$body.addClass('is-loading');
$window.on('load', function() {
$body.removeClass('is-loading');
});
// CSS polyfills (IE<9).
if (skel.vars.IEVersion < 9) $(':last-child').addClass('last-child');
// Fix: Placeholder polyfill.
$('form').placeholder();
// Prioritize "important" elements on mobile.
skel.on('+mobile -mobile', function() {
$.prioritize('.important\\28 mobile\\29', skel.breakpoint('mobile').active);
});
// Scrolly links.
$('.scrolly').scrolly();
// Nav.
var $nav_a = $('#nav a');
// Scrolly-fy links.
$nav_a.scrolly().on('click', function(e) {
var t = $(this),
href = t.attr('href');
if (href[0] != '#') return;
e.preventDefault();
// Clear active and lock scrollzer until scrolling has stopped
$nav_a.removeClass('active').addClass('scrollzer-locked');
// Set this link to active
t.addClass('active');
});
// Initialize scrollzer.
var ids = [];
$nav_a.each(function() {
var href = $(this).attr('href');
if (href[0] != '#') return;
ids.push(href.substring(1));
});
$.scrollzer(ids, { pad: 200, lastHack: true });
// Header (narrower + mobile).
// Toggle.
$('<div id="headerToggle">' + '' + '</div>').appendTo(
$body
);
// Header.
$('#header').panel({
delay: 500,
// hideOnClick: true,
hideOnSwipe: true,
resetScroll: true,
resetForms: true,
side: 'left',
target: $body,
visibleClass: 'header-visible'
});
// Fix: Remove transitions on WP<10 (poor/buggy performance).
if (skel.vars.os == 'wp' && skel.vars.osVersion < 10)
$('#headerToggle, #header, #main').css('transition', 'none');
});
})(jQuery);
example of html that wont work:
<div id="header">
<button
onClick={() => {
console.log('true');
}}
>
Click{' '}
</button>
</div>
$(document).ready(function() {
// This WILL work because we are listening on the 'document',
// for a click on an element with an ID of #test-element
$(document).on("click","#test-element",function() {
alert("click bound to document listening for #test-element");
});
// This will NOT work because there is no '#test-element' ... yet
$("#test-element").on("click",function() {
alert("click bound directly to #test-element");
});
// Create the dynamic element '#test-element'
$('body').append('<div id="test-element">Click mee</div>');
});
This is how to get click functionality with jQuery:
$(function()
{
// Use the .on('click', '#id', function(){}) rather than other options
// for binding click events to dynamically added content as pointed out
// by #Vini
$(document).on("click","#header",function()
{
alert( "Header has been clicked." );
});
$(document).on("click","#buttonToBeClicked",function()
{
alert("Button has been clicked");
});
});
.headerStyle
{
position:relative;
float:left;
width:200px;
height:100px;
background-color:#09f;
text-align:center;
}
.buttonStyle
{
position:relative;
margin: 38px auto;
}
<div id="header" class="headerStyle">
<input type="button" id="buttonToBeClicked" value="clickMe" class="buttonStyle" />
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

HTML Custom Made Menu Control issue

I am having a menu as shown in this fiddle:
http://jsfiddle.net/Gk_999/mtfhptwo/3
(function ($) {
$.fn.menumaker = function (options) {
var cssmenu = $(this), settings = $.extend({
title: "Menu",
format: "dropdown",
sticky: false
}, options);
return this.each(function () {
cssmenu.prepend('<div id="menu-button">' + settings.title + '</div>');
$(this).find("#menu-button").on('click', function () {
$(this).toggleClass('menu-opened');
var mainmenu = $(this).next('ul');
if (mainmenu.hasClass('open')) {
mainmenu.hide().removeClass('open');
}
else {
mainmenu.show().addClass('open');
if (settings.format === "dropdown") {
mainmenu.find('ul').show();
}
}
});
cssmenu.find('li ul').parent().addClass('has-sub');
multiTg = function () {
cssmenu.find(".has-sub").prepend('<span class="submenu-button"></span>');
cssmenu.find('.submenu-button').on('click', function () {
$(this).toggleClass('submenu-opened');
if ($(this).siblings('ul').hasClass('open')) {
$(this).siblings('ul').removeClass('open').hide();
}
else {
$(this).siblings('ul').addClass('open').show();
}
});
};
if (settings.format === 'multitoggle') multiTg();
else cssmenu.addClass('dropdown');
if (settings.sticky === true) cssmenu.css('position', 'fixed');
resizeFix = function () {
if ($(window).width() > 768) {
cssmenu.find('ul').show();
}
if ($(window).width() <= 768) {
cssmenu.find('ul').hide().removeClass('open');
}
};
resizeFix();
return $(window).on('resize', resizeFix);
});
};
})(jQuery);
(function ($) {
$(document).ready(function () {
$("#cssmenu").menumaker({
title: "Menu",
format: "multitoggle"
});
});
})(jQuery);
Now, in jsFiddle, since the menu is responsive, is working fine.
However, if we run it on full screen, upon hover on the parent li list, its children appears compulsorily on the right as shown below.
The problem is that, if we have too many elements in the parent list, & if we hover on the elements at extreme right, its children appear compulsorily on right, & move out of the screen window, as a result, a horizontal scroll-bar appears.
So I want to get the children on the left, rather than right when they are moving out of the screen.
EDIT:
Check fullscreen output here : https://jsfiddle.net/Gk_999/mtfhptwo/3/embedded/result/
Any Help...???
This can only be done with JavaScript is my guess.
Update your ready function with the following mouseenter event. It will fire when somebody moves the mouse over an li with has-sub class.
(function ($) {
$(document).ready(function () {
$("#cssmenu").menumaker({
title: "Menu",
format: "multitoggle"
});
$("li.has-sub").on("mouseenter", function(){
var element = this).find("ul");
//remove the class beforehand so it always defaults to the right.
$(element.removeClass("showleft");
//if the rendered menu and it's page offset are wider then the body
if (element.offsetWidth + element.offset().left > document.body.offsetWidth)
{
element.addClass("showleft");
}
});
});
Add this to the css:
.showleft {
left : -230px !important;
}
It works, look here:
http://jsfiddle.net/mtfhptwo/4/
First, do one thing, get the width of the document using java script and your sub div, set min width of generating div on hover of sub menu if it is greater than minimum height than animate your sub menu(sub div) to wherever you want or you can also give style using java script css property.

only want my function to take place on larger screens when it is no longer a mobile device

Im having trouble getting this to work, so obviously i'm doing something wrong... I created a fade-in hover state on the submenus of my menu, which works perfectly, but when I scale down to mobile view the effect is still relevant, which I do not want as mobile devices don't have hover state. so I rapped my function in a jquery(window).resize function but then it does not work at all.
jQuery(window).resize(function() {
var w = jQuery(window).width();
if (w <= 768 ) {
jQuery('nav.main-nav li').each(function() {
var submenu = jQuery(this).find('ul:first');
jQuery(this).hover(function() {
submenu.css({opacity: 1});
submenu.stop().css({overflow:'hidden', height:'auto', display:'none'}).fadeIn(300, function() {
jQuery(this).css({overflow:'visible', height:'auto', display: 'block'});
});
},
function() {
submenu.stop().css({overflow:'hidden', height:'auto', display:'none'}).fadeOut(300, function() {
jQuery(this).css({overflow:'hidden', display:'none'});
});
});
});
}
});
Instead of using jQuery(window).width();,
try using document.documentElement.clientWidth

Responsive Button using jquery and css

I have a div with a heading using and i have a Vertical Navigation menu in same div.
To make it responsive i use media query and "Display:none and position:abolute" to Navigation Container.
it works perfectly fine till this step.
NOW what i want is that. when i click this heading the the Navigation menu appears and when i click a Link on the Navigation Menu disappears means the menu itself become"Display:none"
I used .toggle() jquery to achieve this.
when this works perfectly fine.
but problem is that i want that this .toggle() function not to work when the width of window is more then 980px;
<h2 id="heading"><span>Office<span class="blue">Managnment</span></span></h2>
<ul id="list">
<li>P</li>
<li>A</li>
<li>N</li>
<li>L</li>
<li>A</li>
<li>R</li>
<li>P</li>
</ul>
and javascript
$(function () {
$("#heading").click(function () {
$("#list").toggle();
});
$("#list").click(function () {
$("#list").toggle('hide');
});
});
and yes i tried if statement to execute this code only when the width is less then 980px but problem is that it only check for width when the page load. i.e if the window is less then 980 on load. script works fine. but when window is more then 980 on load the script do not work even on resizing it to less then 980px.
i dont understand how to achieve this. mainly problem in choosing the condition for the the if else statement.
load the window and check the width
if it is less then 980px execute the script
if it is more then 980 do not execute the script.
on resize of the window check the new width
if it was more then 980 previously
check if the width increased. if it is increased do nothing(script should not work)
check if the width is now less then 980 . START the script.Script should work now.
if it was less then 980 previosly.
check if the width increased more then 980. if it is increased STOP the script. it should not work now
check if the width is now less then 980 . Do nothing. Script should work now.
IN SHORT turn on the toggle function when width less then 980px. and turn the toggle off and set to show when width is more then 980px.
I figured it out as below. It works, but sometimes when i resize slowly it behave strangely.
var $window = $(window),
ONLOADtoggleEnabled = false,
smallscreenbefore = false;
$window.on('resize', function() {
if (smallscreenbefore == false && $window.width() > 1220) {
} else if( smallscreenbefore == false && $window.width() < 1220) {
$( "#Tablist" ).hide(400);
$( "#heading" ).click(function() {
$( "#Tablist" ).toggle(400);
});
$( "#Tablist" ).click(function() {
$( "#Tablist" ).toggle(400);
});
smallscreenbefore = true;
}
else if(smallscreenbefore == true && $window.width() > 1220 ) {
$( "#heading" ).unbind('click');
$( "#Tablist" ).unbind('click');
$( "#Tablist" ).show(400);
smallscreenbefore = false;
}
else if(smallscreenbefore == true && $window.width() < 1220 ) {
smallscreenbefore = false;
}
});
var $window = $(window);
$window.on('load', function() {
if ($window.width() < 1220) {
$( "#heading" ).click(function() {
$( "#Tablist" ).toggle(400);
});
$( "#Tablist" ).click(function() {
$( "#Tablist" ).toggle(400);
});
smallscreenbefore = true;
}
else if($window.width() > 1220) {
smallscreenbefore = false;
}
});
You can listen for the resize event on the window and then use the width to decide what you want to do. I suppose something like this should work:
var MAX_WIDTH = 980,
$window = $(window),
toggleEnabled = false;
$window.on('resize', function() {
// Check window width and check if toggle isn't already enabled
if ($window.width() < MAX_WIDTH) {
// Check if toggle isn't enabled yet
if (!toggleEnabled) {
// Use on() to add eventListener
$("#heading").on('click', function () {
$("#list").toggle();
});
$("#list").on('click', function () {
$("#list").toggle('hide');
});
toggleEnabled = true;
}
} else if (toggleEnabled) {
// Use off() to remove eventListener
$("#heading").off('click');
$("#list").off('click');
// Show the list
$('#list').show();
toggleEnabled = false;
}
$('#output').text('Width: ' + $window.width() + ', toggleEnabled: ' + toggleEnabled);
});
// You can trigger the resize event at the start to set the initial state of the menu
$window.trigger('resize');
Working version with your list: http://jsfiddle.net/srm6p/3/

Jquery UI autocomplete combobox button click event

I'm experiencing weird behavior with jquery ui autocomplete when using it to create a combobox. Whenever I click on the scrollbar to scroll through the list of results AND then click on my combobox button to close the results the results list closes and then opens again. I expect it to close the menu.
Steps to Repro
open jsfiddle demo
Type 'i' in the autocomplete OR hit the dropdown button.
Click on the vertical scroll to scroll the results
Click on the dropdown button
Script to Create Button
this.button = $("<button type='button'> </button>")
.attr({ "tabIndex": -1, "title": "Show all items" })
.insertAfter(input)
.button({
icons: {
primary: "ui-icon-triangle-1-s"
},
text: false
})
.removeClass("ui-corner-all")
.addClass("ui-corner-right ui-button-icon")
.click(function () {
// when i put breakpoint here, and my focus is not on input,
// then this if steatment is false????
if (input.autocomplete("widget").is(":visible")) {
input.autocomplete("close");
return;
}
// work around a bug (likely same cause as #5265)
$(this).blur();
// pass empty string as value to search for, displaying all results
input.autocomplete("search", "");
input.focus();
});
CSS (force long results menu to scroll)
.ui-autocomplete {
max-height: 100px;
overflow-y: auto;
/* prevent horizontal scrollbar */
overflow-x: hidden;
/* add padding to account for vertical scrollbar */
padding-right: 20px;
}
/* IE 6 doesn't support max-height
* we use height instead, but this forces the menu to always be this tall
*/
* html .ui-autocomplete {
height: 100px;
}
My solution could be closing the widget even if focus is transferred to widget itself and not the input element?
Any ideas how to modify this code so it behaves this way?
Based on issues with the various click and mouse events for the automplete widget, I came up with this: jsFiddle example.
jQuery:
var input = $('#txtComplete');
var data = [];
var isOpen = false;
function _init() {
for (var idx = 0; idx <= 100; idx++) {
data.push('item: ' + idx);
};
input.autocomplete({
source: data,
minLength: 0,
open: function(event, ui) {
isOpen = true;
},
select: function(event, ui) {
isOpen = false;
}
});
}
function afterInit() {
var button = $("<button type='button'> </button>").attr("tabIndex", -1).attr("title", "Show all items").insertAfter(input).button({
icons: {
primary: "ui-icon-triangle-1-s"
},
text: false
}).removeClass("ui-corner-all").addClass("ui-corner-right ui-button-icon").click(function(event) {
input.focus();
if (isOpen) {
input.autocomplete("close");
isOpen = false;
} else {
input.autocomplete("search", "");
event.stopImmediatePropagation();
}
});
}
$(window).click(function() {
input.autocomplete("close");
isOpen = false;
});
$(function() {
_init();
afterInit();
});​
The problem is because of a work around in jquery ui autocomplete. There is a mousedown event setup to close the menu under certain conditions. In one of the conditions it checks to see if the item that raised the mousedown is part of the autocomplete widget. If not, it closes the menu. Since you are tacking on combobox behaviour and your button is not part of the autocomplete widget, a click on the button is closing the menu because of this event.
You can see the offending condition with the reason why it is there starting at line 205 in the autocomplete source on github. It is probably worth raising the issue on the jquery ui forums since their combobox demo has this bug too.
UPDATE
This replacement event is based off of jquery-ui 1.8.18. This event has changed and will very likely change again. You might need to update this code manually with each release if you go this route.
You can patch the mousedown event to not close the menu if it was your combo button that was clicked by running the following after you create your autocomplete (jsfiddle demo).
var input = $('#combotextbox').autocomplete(/*options*/);
input.data('autocomplete').menu.element.unbind('mousedown').mousedown(function(event) {
var self = input.data('autocomplete');
event.preventDefault();
// clicking on the scrollbar causes focus to shift to the body
// but we can't detect a mouseup or a click immediately afterward
// so we have to track the next mousedown and close the menu if
// the user clicks somewhere outside of the autocomplete
var menuElement = self.menu.element[0];
if (!$(event.target).closest(".ui-menu-item").length) {
setTimeout(function() {
$(document).one('mousedown', function(event) {
var t = $(event.target);
if (event.target !== self.element[0] && event.target !== menuElement && !$.ui.contains(menuElement, event.target) && !t.hasClass('ui-combo-trigger') && !t.parent().hasClass('ui-combo-trigger')) {
self.close();
}
});
}, 1);
}
// use another timeout to make sure the blur-event-handler on the input was already triggered
setTimeout(function() {
clearTimeout(self.closing);
}, 13);
});
This removes the current mousedown event and then adds it back in with an added check to see if the element that triggered the event or its parent (button clicked or ui-icon inside the button is clicked) has a class ui-combo-trigger.
The code to create your button is relatively unchanged. We just need to add the new class ui-combo-trigger.
var button = $("<button type='button'> </button>").attr("tabIndex", -1).attr("title", "Show all items").insertAfter(input).button({
icons: {
primary: "ui-icon-triangle-1-s"
},
text: false
}).removeClass("ui-corner-all").addClass("ui-corner-right ui-button-icon ui-combo-trigger").click(function(event) {
// when i put breakpoint here, and my focus is not on input,
// then this if steatment is false????
if (input.autocomplete("widget").is(":visible")) {
input.autocomplete("close");
return;
}
// work around a bug (likely same cause as #5265)
$(this).blur();
// pass empty string as value to search for, displaying all results
input.autocomplete("search", "");
input.focus();
event.stopImmediatePropagation();
});
Try this jsfiddle. I think it ll help you.
var input = $('#txtComplete');
var data = [];
var openCheck = false;
function _init() {
for (var idx = 0; idx <= 100; idx++) {
data.push('item: ' + idx);
};
input.autocomplete({
source: data,
minLength: 0,
open: function(event, ui) {
openCheck = true;
},
select: function(event, ui) {
openCheck = false;
}
});
}
function afterInit() {
var button = $("<button type='button'> </button>").attr("tabIndex", -1).attr("title", "Show all items").insertAfter(input).button({
icons: {
primary: "ui-icon-triangle-1-s"
},
text: false
}).removeClass("ui-corner-all").addClass("ui-corner-right ui-button-icon").click(function(event) {
if (openCheck) {
input.autocomplete("close");
openCheck = false;
} else {
input.autocomplete("search", "");
}
});
}
$(function() {
_init();
afterInit();
});
Brian explained the problem very good. With jquery ui 11 you can do something like:
wasOpen = false;
$button
.mousedown(function() {
wasOpen = input.autocomplete( "widget" ).is( ":visible" );
})
.click(function() {
input.focus();
// Close if already visible
if ( wasOpen ) {
return;
}
see example at http://jqueryui.com/autocomplete/#combobox

Categories