Close a div when clicking outside it

Hi :slight_smile:

I have a time picker, where the user clicks the icon then a div (with a list of times) pops up. My problem is that if i click else where on the page, the time picker div stays open. This happens on all browsers (FF, IE, Safari, Opera)

I have been trawling the net to find something that will close this div when the user clicks elsewhere on the page and this seems to be pretty much what i want to do


<script type="text/javascript">
	
$(document).click(function(){ 
		jQuery(".time-picker").click(function(){ return false; });
		jQuery(document).bind("click", function() { jQuery(".time-picker").fadeOut(); /* Fade out when user leaves time-picker div*/
		
		});
		
	});
</script>

the only thing is that it only works the first time. If i want to amend the time at any point, then the div fades out automatically. Is there anyway to reset this jquery once the user has clicked away from the div?

Any help is greatly appreciated.
gillian

Hey Raffles,

Thanks so much for all your help. :smiley: Finally got it to work, very stupid of me, never noticed the links had different ID’s. Works for all browsers too (FF, IE6/7, Safari and Opera).

Thanks again
gillian


<script type="text/javascript"> 
	$(document).ready(function() { 
	  $('#openTimePicker,#closeTimePicker').click(function() {
		if ($(this).next().is(':visible')) $(this).next().fadeOut();
		else $(this).next().fadeIn();
	  });
	  $(document).click(function(e) {
		if ($(e.target).is('#closeTimePicker,#openTimePicker, .time-picker, .time-picker *'))  return false;
		else $('.time-picker').fadeOut();
	  }); 
	}); 
	</script>

That code looks very dodgy, as it’s going to be recursively binding click events on the document. It’s fading out automatically the second time because when you click the link to amend the time, that link is in the document, so the fadeOut event handler is also called.

I think this needs to be done differently.

Try this out:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"  "http://www.w3.org/TR/html4/strict.dtd"> 
<html> 
<head> 
<title>Hi</title> 
<style type="text/css">
div {
  padding:1.4em;
} 
.time-picker {
  display:none;
  border:1px solid blue;
  background:cyan;
  width:100px;
  height:50px;
  float:left;
  padding:0
}
.timepicklink {
  float:left;
  clear:left;
} 
</style> 
<script type="text/javascript"  src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>  
<script type="text/javascript"> 
$(document).ready(function() {
  $('.timepicklink').click(function() {
    if ($(this).next().is(':visible')) $(this).next().fadeOut();
    else $(this).next().fadeIn();
  });
  $(document).click(function(e) {
    if ($(e.target).is('.timepicklink, .time-picker, .time-picker *'))  return false;
    else $('.time-picker').fadeOut();
  }); 
}); 
</script> 
<head> 
<body> 
<h1>Time picking</h1> 
<div>
  <a href="#time-picker" class="timepicklink">choose time  1</a>
  <div class="time-picker">time picker 1  <span>here</span></div>
</div>
<div>
  <a href="#time-picker" class="timepicklink">choose time  2</a>
  <div class="time-picker">time picker 2 here</div>
</div>
<div>
  <a href="#time-picker" class="timepicklink">choose time  3</a>
  <div class="time-picker">time picker 3 here</div>
</div> 
</body> 
</html>

The DOM traversal will have to be different if your HTML is any different. If you show some sample HTML, I can change it to suit it.

Thanks Raffles,

This seems much better, only one slight problem, i have two time pickers on the page and the first one just fades out straight away, second one works perfect! :slight_smile:

Here is the code that i’m working with.



<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
	<head>

		<title>Help </title>
		
		<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
		<script type="text/javascript" src="http://jquery-timepicker.googlecode.com/files/jquery.timepicker.js"></script> 

		<script type="text/javascript">
		<!-- compressed timepicker code -->
		(function($){$.fn.timePicker=function(targetElmSelector,options){var settings=$.extend({},$.fn.timePicker.defaults,options);return this.each(function(){$.timePicker(this,targetElmSelector,settings)})};$.timePicker=function(elm,targetElmSelector,settings){var e=$(elm)[0];var targetElm=$(targetElmSelector)[0];return e.timePicker||(e.timePicker=new jQuery._timePicker(e,targetElm,settings))};$._timePicker=function(elm,targetElm,settings){var tpOver=false;var keyDown=false;var startTime=timeToDate(settings.startTime,settings);var endTime=timeToDate(settings.endTime,settings);$(elm).attr('autocomplete','OFF');var times=[];var time=new Date(startTime);while(time<=endTime){times[times.length]=formatTime(time,settings);time=new Date(time.setMinutes(time.getMinutes()+settings.step))}var $tpDiv=$('<div class="time-picker'+(settings.show24Hours?'':' time-picker-12hours')+'"></div>');var $tpList=$('<ul></ul>');for(var i=0;i<times.length;i++){$tpList.append("<li>"+times[i]+"</li>")}$tpDiv.append($tpList);var elmOffset=$(elm).offset();$tpDiv.appendTo('body').css({'top':elmOffset.top,'left':elmOffset.left}).hide();$tpDiv.mouseover(function(){tpOver=true}).mouseout(function(){tpOver=false});$("li",$tpList).mouseover(function(){if(!keyDown){$("li.selected",$tpDiv).removeClass("selected");$(this).addClass("selected")}}).mousedown(function(){tpOver=true}).click(function(){setTimeVal(targetElm,this,$tpDiv,settings);tpOver=false});var showPicker=function(){if($tpDiv.is(":visible")){return false}$("li",$tpDiv).removeClass("selected");$tpDiv.show();var time=elm.value?timeStringToDate(elm.value,settings):startTime;var startMin=startTime.getHours()*60+startTime.getMinutes();var min=(time.getHours()*60+time.getMinutes())-startMin;var steps=Math.round(min/settings.step);var roundTime=normaliseTime(new Date(0,0,0,0,(steps*settings.step+startMin),0));roundTime=(startTime<roundTime&&roundTime<=endTime)?roundTime:startTime;var $matchedTime=$("li:contains("+formatTime(roundTime,settings)+")",$tpDiv);if($matchedTime.length){$matchedTime.addClass("selected");$tpDiv[0].scrollTop=$matchedTime[0].offsetTop}return true};$(elm).focus(showPicker).click(showPicker);$(elm).blur(function(){if(!tpOver){$tpDiv.hide()}});var event=($.browser.opera||$.browser.mozilla)?'keypress':'keydown';$(elm)[event](function(e){var $selected;keyDown=true;var top=$tpDiv[0].scrollTop;switch(e.keyCode){case 38:if(showPicker()){return false};$selected=$("li.selected",$tpList);var prev=$selected.prev().addClass("selected")[0];if(prev){$selected.removeClass("selected");if(prev.offsetTop<top){$tpDiv[0].scrollTop=top-prev.offsetHeight}}else{$selected.removeClass("selected");prev=$("li:last",$tpList).addClass("selected")[0];$tpDiv[0].scrollTop=prev.offsetTop-prev.offsetHeight}return false;break;case 40:if(showPicker()){return false};$selected=$("li.selected",$tpList);var next=$selected.next().addClass("selected")[0];if(next){$selected.removeClass("selected");if(next.offsetTop+next.offsetHeight>top+$tpDiv[0].offsetHeight){$tpDiv[0].scrollTop=top+next.offsetHeight}}else{$selected.removeClass("selected");next=$("li:first",$tpList).addClass("selected")[0];$tpDiv[0].scrollTop=0}return false;break;case 13:if($tpDiv.is(":visible")){var sel=$("li.selected",$tpList)[0];setTimeVal(targetElm,sel,$tpDiv,settings)}return false;break;case 27:$tpDiv.hide();return false;break}return true});$(elm).keyup(function(e){keyDown=false});this.getTime=function(){return timeStringToDate(elm.value,settings)};this.setTime=function(time){elm.value=formatTime(normaliseTime(time),settings);$(elm).change()}};$.fn.timePicker.defaults={step:30,startTime:new Date(0,0,0,0,0,0),endTime:new Date(0,0,0,23,30,0),separator:':',show24Hours:true};function setTimeVal(elm,sel,$tpDiv,settings){elm.value=$(sel).text();$(elm).change();if(!$.browser.msie){elm.focus()}$tpDiv.hide()}function formatTime(time,settings){var h=time.getHours();var hours=settings.show24Hours?h:(((h+11)&#37;12)+1);var minutes=time.getMinutes();return formatNumber(hours)+settings.separator+formatNumber(minutes)+(settings.show24Hours?'':((h<12)?' AM':' PM'))}function formatNumber(value){return(value<10?'0':'')+value}function timeToDate(input,settings){return(typeof input=='object')?normaliseTime(input):timeStringToDate(input,settings)}function timeStringToDate(input,settings){if(input){var array=input.split(settings.separator);var hours=parseFloat(array[0]);var minutes=parseFloat(array[1]);if(!settings.show24Hours){if(hours===12&&input.substr('AM')!==-1){hours=0}else if(hours!==12&&input.indexOf('PM')!==-1){hours+=12}}var time=new Date(0,0,0,hours,minutes,0);return normaliseTime(time)}return null}function normaliseTime(time){time.setFullYear(2001);time.setMonth(0);time.setDate(0);return time}})(jQuery);	
		</script>

		<script type="text/javascript"> 
		$(document).ready(function() {
		  $('#closeTimePicker').click(function() {
			if ($(this).next().is(':visible')) $(this).next().fadeOut();
			else $(this).next().fadeIn();
		  });
		  $(document).click(function(e) {
			if ($(e.target).is('#closeTimePicker, .time-picker, .time-picker *'))  return false;
			else $('.time-picker').fadeOut();
		  }); 
		}); 
		</script>
		
		<script type="text/javascript">
			jQuery(function() {
				$("#openTimePicker").timePicker("#openTime");
				$("#closeTimePicker").timePicker("#closeTime");
			});
		</script>

		<!-- time picker css-->
		<style>
		div.time-picker {
			position: absolute;
			height: 200px;
			width:7.25em;
			overflow: auto;
			background: #fff;
			border: 1px solid #000;
			z-index: 99;
		}
		div.time-picker-12hours {width:6em;}

		div.time-picker ul {
			list-style-type: none;
			margin: 0;
			padding: 0;
			list-style-position:outside
		}
		div.time-picker li {
			padding: 1px;
			cursor: pointer;
		}
		div.time-picker li.selected {
			background: #316AC5;
			color: #fff;
		}
		</style>


	</head>
	<body>
		<form name="Form" method="post" action="" id="Form">
			<div id="details">
				<fieldset>
					<legend>Details</legend>
					<div class="timeRow">
						<div class="col-timeFrom">
							<label for="openTime">Time From:</label>
							<input type="text" name="openTime" maxlength="5" size="5" value="" onblur="javascript:this.value=this.value.replace(/^\\s+|\\s+$/g,'')" onfocus="javascript:this.value=this.value.replace(/^\\s+|\\s+$/g,'')" class="text" id="openTime" />
							<img src="/images/timepicker.gif" alt="icon" title="time picker" width="16" height="16" id="openTimePicker" style="border:1px solid red;"/>
						</div>
						<div class="col-timeTo">
							<label for="closeTime" class="innerlabel">Time To:</label>
							<input type="text" name="closeTime" maxlength="5" size="5" value="" onblur="javascript:this.value=this.value.replace(/^\\s+|\\s+$/g,'')" onfocus="javascript:this.value=this.value.replace(/^\\s+|\\s+$/g,'')" class="text" id="closeTime" />
							<img src="/images/timepicker.gif" alt="icon" title="time picker" width="16" height="16" id="closeTimePicker" style="border:1px solid red;"/>
						</div>
					</div>
				</fieldset>
			</div>
		</form>
	</body>
</html>


Any more help much appreciated
gillian