Reputation: 455
I have a working code where I can dynamically add input fields which can be used for auto-completion using AJAX. Though working, there are limitations. After adding more fields, placement of the autofill is incorrect, as demonstrated in this image:
The results are not showing under the current input field but rather under the last one. Lastly, once the user adds too many input fields and starts removing them, the autocomplete feature stops working altogether.
HTML Code:
<div class="item form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12">Case Category <button style="margin-top: 5px;" id = "add_field" class="add_field btn btn-primary btn-xs">+</button></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input id="search_keyword_idd" class="search_keywordd form-control col-md-5 col-xs-12" name="category[]" required="required" type="text">
<input type="hidden" name="catID[]" id="catID"/>
<div id="resultd"></div>
</div>
</div>
<div class = "t"></div>
Javascript/jQuery Pt. 1: (on the first input field)
<script type="text/javascript">
$(function(){
$(".search_keywordd").keyup(function()
{
var search_keyword_value = $(this).val();
var dataString = 'search_keyword='+ search_keyword_value;
if(search_keyword_value!='')
{
$.ajax({
type: "POST",
url: "../resources/ajax-search/case_category.php",
data: dataString,
cache: false,
success: function(html)
{
$("#resultd").html(html).show();
}
});
}
return false;
});
jQuery("#resultd").on("click", ".show", function(e){
var showName = $('.returnName',this).text();
var showId = $('.returnID',this).text();
$('#search_keyword_idd').val(showName);
$('#catID').val(showId);
});
jQuery(document).on("click", function(e) {
var $clicked = $(e.target);
if (! $clicked.hasClass("search_keywordd")){
jQuery("#resultd").hide();
}
});
$('#search_keyword_idd').click(function(){
jQuery("#resultd").show();
});
});
</script>
Javascript/jQuery Pt. 2: (on the input fields that the user want to add)
$(document).ready(function() {
var max_fields = 10; //maximum input boxes allowed
var wrapper3 = $(".t"); //Fields wrapper
var add_button3 = $("#add_field"); //Add button ID
var z = 1; //initlal text box count
$(add_button3).click(function(e){ //on add input button click
e.preventDefault();
if(z < max_fields){ //max input box allowed
z++; //text box increment
$(wrapper3).append('<div class="item form-group"><label class="control-label col-md-3 col-sm-3 col-xs-12"></label><div class="col-md-6 col-sm-6 col-xs-12"><input id="search_keyword_idd'+z+'" class="search_keywordd'+z+' form-control col-md-5 col-xs-12" name="category['+z+']" required="required" type="text"><input type="hidden" name="catID['+z+']" id="catID'+z+'"/><div id="resultd'+z+'"></div><button class="remove btn btn-dark">Remove</button></div></div>'); //add input box
$("#resultd"+z+"").css({"margin-top": "40px", "position": "absolute", "display": "none", "border-top": "0px", "overflow": "visible", "border": "1px #F0F0F0 solid", "float": "left", "padding": "0"});
//$(".show"+z+"").css("cursor:", "default", "margin:", "0", "display:", "none", "background:", "#F7F7F7", "width:", "548px", "border-bottom:", "#F0F0F0 1px solid", "position:", "relative", "z-index:", "10");
}
$(".search_keywordd"+z+"").keyup(function() {
var search_keyword_value = $(this).val();
var dataString = 'search_keyword='+ search_keyword_value;
if(search_keyword_value!='') {
$.ajax({
type: "POST",
url: "../resources/ajax-search/case_category.php",
data: dataString,
cache: false,
success: function(html)
{
$("#resultd"+z+"").html(html).show();
}
});
}
return false;
});
jQuery("#resultd"+z+"").on("click", ".show", function(e){
var showName = $('.returnName',this).text();
var showId = $('.returnID',this).text();
$('#search_keyword_idd'+z+'').val(showName);
$('#catID'+z+'').val(showId);
});
jQuery(document).on("click", function(e) {
var $clicked = $(e.target);
if (! $clicked.hasClass("search_keyword"+z+"")){
jQuery("#resultd"+z+"").hide();
}
});
$('#search_keyword_idd'+z+'').click(function(){
jQuery("#resultd"+z+"").show();
});
$(wrapper3).on("click",".remove", function(e){ //user click on remove text
e.preventDefault(); $(this).parent('div').parent('div').remove(); y--;
});
});
});
PHP:
<?php
include('config.php'); //working just fine
if($_POST)
{
if($_POST['search_keyword']) // returns an error from answer 1
{
$similar = mysql_real_escape_string($_POST['search_keyword']);
$result=mysqli_query($conn, "SELECT * FROM casecategory WHERE (caseCategoryName like '" . $_POST["search_keyword"] . "%')");
if (mysqli_num_rows($result) > 0) {
while($row=mysqli_fetch_array($result))
{
?>
<div class="show" align="left">
<span class="returnName"><?php echo $row["caseCategoryName"] ?></span>
<span class="returnID" style="display:none"><?php echo $row['idCaseCategory'];?></span>
</div>
<?php
}
}
else {
?>
<div class="show" align="left">
<span class="returnMessage">No matching records found.</span>
</div>
<?php
}
}
mysqli_close($conn);
}
?>
I am at a loss as to which part(s) are not working and how to fix it so that:
onfocus
inputUpvotes: 1
Views: 3024
Reputation: 12505
See if this is what you are looking for. The HTML appears to be correct when looking at the console, but I don't have your css, so it's hard to say. The changes:
1) I have removed all the id
values in favor of using just classes. That way you don't have to worry about id
values...what works for a static block of html, will work for a dynamic block so note all the changes in the html
2) I have consolidated all js to just what I have pasted below
3) There is only one instance of ajax
4) All clicks are relegated to one if/else/else if
condition:
<div class="item form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12">Case Category <button style="margin-top: 5px;" class="add_field btn btn-primary btn-xs">+</button></label>
<div class="col-md-6 col-sm-6 col-xs-12 search_wrap">
<input class="search_keyword form-control col-md-5 col-xs-12" name="category[]" required="required" type="text">
<input type="text" name="catID[]" />
<div class="resultd"></div>
</div>
</div>
<div class = "t"></div>
Javascript
<script type="text/javascript">
// I have created an ajax instance incase you want to use ajax else where
// You just make a new instance instead of copy/pasting same scripts
var AjaxEngine = function()
{
$ = arguments[0];
var url = '../resources/ajax-search/case_category.php';
// Allows you to use a different destination for the call
this.useUrl = function()
{
if(arguments.length === 1) {
url = arguments[0];
}
return this;
};
this.ajax = function(data,userFunc)
{
$.ajax({
type: "POST",
url: url,
// Send data object instead of string
data: data,
cache: false,
// Not hardcoding a response will allow
// for flexibility
success: function(response) {
userFunc(response);
}
});
}
}
// I just created a php-like empty function
function empty(val)
{
return (val !== null && val !== false && val !== '')? false : true;
}
// Group everything into one document ready
$(function(){
// Hide dropdown
$(this).click(function(e) {
var target = $(e.target);
if(!target.hasClass('resultd')) {
$('.resultd').hide();
}
});
// Create ajax engine
var Remote = new AjaxEngine(jQuery);
// run the keyword search, I would use this here so you can
// get all instances of keyup, both dynamic and static instances
$(this).on('keyup',".search_keyword",function(e){
var sTerm = $(this).val();
var thisWrap = $(this).parents('.form-group').find('.resultd');
if(!empty(sTerm)) {
Remote.ajax({ search_word:sTerm },function(response) {
thisWrap.html(response).show();
});
}
});
// Create the copy-to function
function copyTo(thisShow)
{
var showName = thisShow.find('.returnName').text();
var showId = thisShow.find('.returnID').text();
var thisWrap = thisShow.parents('.search_wrap').find('input[name=category\\[\\]]');
thisWrap.val(showName);
thisWrap.next().val(showId);
};
// Create the add field function
function addNewField(obj,max_fields,z)
{
if(z < max_fields){
obj.append('<div class="item form-group"><label class="control-label col-md-3 col-sm-3 col-xs-12"></label><div class="col-md-6 col-sm-6 col-xs-12 search_wrap"><input class="search_keyword search_keywordd form-control col-md-5 col-xs-12" name="category[]" required="required" type="text"><input type="text" name="catID[]" /><div class="resultd"></div><button class="remove btn btn-dark">Remove</button></div></div>'); //add input box
var lastRes = obj.find(".resultd");
lastRes.last().css({"margin-top": "40px", "position": "absolute", "display": "none", "border-top": "0px", "overflow": "visible", "border": "1px #F0F0F0 solid", "float": "left", "padding": "0"});
z++;
// return the auto-increment count
return z;
}
// return the max count
return max_fields;
}
var settings = {
z: 1,
max_fields: 10
}
$(this).on("click", '.show,.search_keyword,.add_field,.remove', function(e) {
// Target the click
var clicked = $(this);
// Hide by default
$(".resultd").hide();
// Run the copyto
if(clicked.hasClass("show")) {
copyTo(clicked);
}
// Show the search window
else if(clicked.hasClass("search_keyword")) {
clicked.parents('.search_wrap').find('.resultd').show();
}
// Add fields
else if(clicked.hasClass("add_field")) {
settings.z = addNewField($(".t"),settings.max_fields,settings.z);
}
// remove fields
else if(clicked.hasClass("remove")) {
e.preventDefault();
clicked.parent('div').parent('div').remove();
settings.z--;
}
});
});
</script>
Upvotes: 2