I have an input field which fires an AJAX request and fills a <div> ($container)
element with HTML.
The JSON node response.resultsHTML
contains the HTML that is to be added to $container
, the HTML looks like:
<div class="js_livesearch livesearch">
<div class="js_livesearch_results livesearch_results">
<div class="js_livesearch_result livesearch_result" data-id="3">item_1</div>
<div class="js_livesearch_result livesearch_result" data-id="2">item_2</div>
<div class="js_livesearch_result livesearch_result" data-id="1">item_3</div>
<div class="js_livesearch_result livesearch_result" data-id="4">item_4</div>
</div>
</div>
The JavaScript/jQuery that performs the AJAX call and adds the AJAX response's HTML to the DOM looks like the following:
$liveSearchTrigger.on('input', function () {
var search = this.value;
if (search) {
$.ajax({
url: '/ajax/livesearch/' + $(this).data('identifier'),
type: 'POST',
dataType: 'JSON',
data: {
search: search
},
success: function (response) {
if (response.success) {
if (response.resultsCount) {
$container.html(response.resultsHTML);
$container.find('.js_livesearch_result').each(function() {
var $result = $(this);
//this is being called correctly for EVERY SINGLE $result
alert("found: " + $result.text());
//this is only sporadically bound to $result, not every single $result has the click handler - WHY?
$result.on('click', function() {
$liveSearchTrigger.val($result.text());
alert('attempting to set ' + $result.text());
});
});
reLayout();
$container.slideDown(150);
} else {
$container.slideUp(150);
}
}
}
});
} else {
$container.slideUp(150);
}
});
Now, after adding the newly generated HTML to the DOM using $container.html(response.resultsHTML);
I want to bind a click event to every single $('.js_livesearch_result')
element.
In the $container.find('.js_livesearch_result').each(function() { ... });
scope, the alert is called on every .js_livesearch_result
item and it alerts 'item_1', item_2', [...] for all elements, but the $result.on('click', function() { ... });
is not bound to all of them. Sometimes only the first two, sometimes three have the click event bound.
What am I doing wrong trying to bind the click event to the dynamically generated .js_livesearch_result
elements and how do I bind the event properly, so that every single .js_livesearch_result
element has the click handler bound?
EDIT:
Here is some more (updated) code hence I still can't get the $('.js_livesearch_result').on('click', function() {...});
to work properly:
The $liveSearchTrigger
element's HTML:
<input class="js_livesearch" type="text" name="key" value="" data-identifier="langkey" autocomplete="off" />
The response.resultsHTML
structure, which will be appended to $container
:
<div class="js_livesearch_results livesearch_results">
<div class="js_livesearch_result livesearch_result" data-id="3">menu_code</div>
<div class="js_livesearch_result livesearch_result" data-id="2">menu_gallery</div>
<div class="js_livesearch_result livesearch_result" data-id="1">menu_home</div>
<div class="js_livesearch_result livesearch_result" data-id="4">menu_user</div>
</div>
The page.js
to initialize the plugin:
$(document).ready(function() {
$('.js_livesearch').liveSearch();
});
The livesearch.js
(the plugin):
(function ($, window) {
$.fn.liveSearch = function (options) {
var defaults = {
highlightCSS: {
'background-color': "lightgoldenrodyellow",
}
};
var settings = $.extend({}, defaults, options);
var $liveSearchTrigger = $(this);
var searchUID = Math.floor(Math.random() * 26) + Date.now();
var $container = $('.js_livesearch_uid' + searchUID);
if (!$container.length) {
var $elem = $('<div>').addClass('js_livesearch_uid' + searchUID).addClass('hidden');
$('body').append($elem);
$container = $('.js_livesearch_uid' + searchUID);
}
$liveSearchTrigger.on('input', function () {
var search = this.value;
if (search) {
$.ajax({
url: '/ajax/livesearch/' + $(this).data('identifier'),
type: 'POST',
dataType: 'JSON',
data: {
search: search
},
success: function (response) {
if (response.success) {
if (response.resultsCount) {
$container.html(response.resultsHTML);
//this works fine if uncommented, every single
//element gets a highlight applied
// $container.find('.js_livesearch_result').each(function() {
// $(this).highlight(search, settings.highlightCSS);
// });
//this does not work consistently, sometimes the first 3 (out of 4)
//items will bind the click handler sometimes only the first two
//elements will bind the click handler
$container.on('click', '.js_livesearch_result', function() {
console.log('Clicked: ' + $(this).text());
});
//another test which didn't work:
// $container.find('.js_livesearch_result').each(function() {
// $(this).unbind('click.resultItemClick').bind('click.resultItemClick', function() {
// console.log('Clicked: ' + $(this).text());
// });
// });
reLayout();
$container.slideDown(150);
$container.removeClass('hidden');
} else {
$container.slideUp(150);
$container.addClass('hidden');
}
}
}
});
} else {
$container.slideUp(150);
$container.addClass('hidden');
}
});
$(window).resize(function() {
reLayout();
});
$liveSearchTrigger.on('focus', function() {
reLayout();
$container.slideDown(150);
$container.removeClass('hidden');
});
$liveSearchTrigger.on('blur', function() {
$container.slideUp(150);
$container.addClass('hidden');
});
function reLayout() {
var position = $liveSearchTrigger.position();
var layoutCSS = {
'position': 'absolute',
'z-index': '1000',
'top': (position.top + $liveSearchTrigger.outerHeight()) + 'px',
'left': position.left + 'px',
'width': $liveSearchTrigger.outerWidth() + 'px'
};
$container.css(layoutCSS);
}
return this;
};
}(jQuery, window));
How do I bind a click event to all .js_livesearch_result
elements that are being added to the DOM via AJAX?