Isabella
Isabella

Reputation: 455

Dynamic form input fields and autocomplete using AJAX

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: enter image description here

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:

  1. The auto-complete box displays under the current onfocus input
  2. When max-amount of inputs are added and then removed, that the auto-complete feature still works

Upvotes: 1

Views: 3024

Answers (1)

Rasclatt
Rasclatt

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

Related Questions