Reputation: 3457
I have an input field. When user focuses on that input a unordered list appears beneath that input.
When user clicks on one of the list children that data is inserted into input and unordered list is hidden.
CURRENT PROBLEM
If a user clicks on input , but doesn't choose any of the options and then click somewhere else in the document the unordered list will remain shown.
I don't if there's some kind of event I'm missing that I could use to solve this.
$('body').on('focus blur click', '.autocomplete input , .autocomplete ul, .autocomplete li' , function() {
if (event.type === 'focus' && event.target.nodeName == 'INPUT') {
$(this).siblings('ul').show();
} else if ((event.type === 'blur' || event.type === 'click' ) && event.target.nodeName == 'LI') {
$(this).parent('ul').hide();
}
});
$('body').on('click' ,'li' ,function() {
$('#P1_FIRST_NAME').val($(this).attr('data-value'));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
<div class="input__container autocomplete">
<div class="input__label__container">
<label for="P1_FIRST_NAME" tabindex="999">Autocomplete</label>
</div>
<input type="text" id="P1_FIRST_NAME" class="text_field" autocomplete="off" value="">
<ul for="P1_FIRST_NAME" style="display: none;">
<li tabindex="1" data-value="MAD">Madder</li>
<li tabindex="1" data-value="SAD">Sandy</li>
</ul>
</div>
Upvotes: 0
Views: 270
Reputation: 338228
Notes
.on()
to pass in multiple event handlers. Don't use if/else to switch between different behaviors for different events.data-
attribute (see targetSelector
below)..closest()
to navigate to the correct elements.<ul>
so that it does not push down content below.$('body')
.on({
'focus': function() {
var $ul = $(this).closest('.autocomplete').find('ul');
$ul.width( $(this).width() ).show();
},
'blur': function() {
var $ul = $(this).closest('.autocomplete').find('ul');
setTimeout(function () { $ul.fadeOut('fast'); }, 250);
}
}, '.autocomplete input')
.on('click', '.autocomplete li', function() {
var targetSelector = $(this).closest('ul').data('for');
$(targetSelector).val( $(this).data('value') );
$(this).closest('ul').fadeOut('fast');
});
.autocomplete {
position: relative;
}
.autocomplete ul {
display: none;
position: absolute;
margin: 0;
padding: 0;
list-style: none;
background-color: white;
box-shadow: 4px 4px 5px -2px rgba(0,0,0,0.59);
border: 1px solid #efefef;
}
.autocomplete ul li {
padding: 3px;
cursor: pointer;
}
.autocomplete ul li:hover {
background-color: #FCF3CF;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="input__container autocomplete">
<div class="input__label__container">
<label for="P1_FIRST_NAME" tabindex="999">Autocomplete</label>
</div>
<input type="text" id="P1_FIRST_NAME" class="text_field" autocomplete="off" value="">
<ul data-for="#P1_FIRST_NAME">
<li data-value="MAD">Madder</li>
<li data-value="SAD">Sandy</li>
</ul>
</div>
<p>content below content below content below content below content below</p>
Upvotes: 1
Reputation: 2963
you'd need to use "this" selectors if there's more than one on a page, but here's one way to click the field to show the ul list and click away from the ul list to hide it again:
$( ".text_field" ).click(function() {
$('ul').show();
});
$(document).mouseup(function(e) {
var container = $("ul");
if (!container.is(e.target) && container.has(e.target).length === 0) {
$('ul').hide();
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
<div class="input__container autocomplete">
<div class="input__label__container">
<label for="P1_FIRST_NAME" tabindex="999">Autocomplete</label>
</div>
<input type="text" id="P1_FIRST_NAME" class="text_field" autocomplete="off" value="">
<ul for="P1_FIRST_NAME" style="display: none;">
<li tabindex="1" data-value="MAD">Madder</li>
<li tabindex="1" data-value="SAD">Sandy</li>
</ul>
</div>
Upvotes: 0
Reputation: 68393
check this fiddle
you need to bind a click event at html
and stop event propagation at input
and ul
level
$('body').on('focus blur click', '.autocomplete input , .autocomplete ul, .autocomplete li' , function(e) {
if (event.type === 'focus' && event.target.nodeName == 'INPUT') {
$(this).siblings('ul').show();
} else if ((event.type === 'blur' || event.type === 'click' ) && event.target.nodeName == 'LI') {
$(this).parent('ul').hide();
}
e.stopPropagation();
});
$('body').on('click' ,'li' ,function(e) {
$('#P1_FIRST_NAME').val($(this).attr('data-value'));
e.stopPropagation();
});
$("html").click( function(e) {
$('ul').hide();
});
Upvotes: 2