본문 바로가기
프로그래밍/자바스크립트

jQuery UI autocomplete(입력필드 자동완성) 사용하기

by pentode 2018. 4. 20.

입력 필드에 타이핑을 하면 관련 정보를 보여주고 선택할 수 있는 기능이 많이 사용됩니다. jQuery UI에서 제공되는 autocomplete 기능을 사용해서 이 기능을 구현해 봅니다.



1. 필요한 파일 인클루드하기


jQuery  UI 스타일 시트 파일과 jQuery 파일, jQuery UI 파일이 필요합니다. 각각은 다운로드 받아서 사용해도 되고 CDN 을 이용해서 사용해도 됩니다. 이 예제에서는 CDN을 사용했습니다.


<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">

<script src="https://code.jquery.com/jquery-1.12.4.js"></script>

<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>



2. 기본 기능 사용하기


<script type="text/javascript">

//<![CDATA[

$(function() {

    var availableCity = ["서울","부산","대구","광주","울산"];

    $("#city").autocomplete({

        source: availableCity,

        select: function(event, ui) {

            console.log(ui.item);

        },

        focus: function(event, ui) {

            return false;

            //event.preventDefault();

        }

    });

});

//]]>

</script>


<div class="ui-widget">

  <label for="city">도시: </label>

  <input id="city">

</div>


id가 city 인 입력 필드에 자동완성기능을 만듭니다.


- $("#city").autocomplete() : 자동완성기능을 만듭니다.

- source: avalibleCity : 타이핑시 보여질 내용 입니다.

- select: function(event, ui){}; : 아이템 선택시 실행됩니다. ui.item 이 선택된 항목을 나타내는 객체입니다. 선택된 옵션의 label과 value 값을 가집니다.

- focus: function(event, ui){ return false;} : jQuery UI autocomplete를 한글과 사용할때 커서를 사용해서 아이템을 선택하면 나머지가 사라져 버리는 버그가 있습니다. 이 코드를 추가하면 해결됩니다. return false; 또는 event.preventDefault(); 를 사용해서 이벤트를 무시하게 하는 것입니다.





3. 원격 데이터 조회


입력한 데이터를 서버로 보내 데이터를 조회해서 자동완성으로 출력하는 예제입니다. 서버쪽에서는 검색된 데이터를 json 형식으로 보냅니다.


<script type="text/javascript">

//<![CDATA[

$(function() {

    $("#city").autocomplete({

        source: "search.php",

        minLength: 2,

        response: function(event, ui) {

            console.log(ui);

        },

        select: function(event, ui) {

            console.log("Selected:" + ui.item.value);

        },

        focus: function(event, ui) {

            return false;

        }

    });

});

//]]>

</script>


- source: "search.php" : 입력시 서버쪽에서 실행될 스크립트 입니다.

- minLength: 2 : 두자 이상이 입력될 때 서버로 요청을 보냅니다. 영어는 알파벳 두자, 한글을 글자 두자 입니다. 서버쪽으로의 트래픽도 줄이고, 검색된 데이터의 양이 너무 많아지는 것을 방지하는 역할을 합니다.

- response: function(event, ui) {} : 서버에서 응답이 오면 화면에 리스트를 보여주기 전에 실행됩니다. ui는 서버로 부터 보내온 배열 데이터입니다.

- select: function(event, ui) {} : 검색된 리스트에서 항목을 선택하면 실행됩니다.

- focus: function(event, ui) {return false;} : 한글 리스트에서 선택시 리스트가 사라지는 오류 방지용 입니다.



4. 원격 데이터 조회시 서버측 코드 입니다.


예제용으로 간단히 배열에서 찾는 것으로 만들었습니다. 실제 응용에서는 데이터베이스에서 검색하여 반환하는등의 코드가 될 것입니다.


jQuery UI autocomplete에서 원격으로 요청시 검색어의 파라미터를 "term" 입니다. 코드 설명은 주석을 참조해 주세요.


<?php

// 컨텐츠 타입을 json으로 지정합니다.

header("Content-Type: application/json");


// 검색될 샘플 데이터 입니다.

$cities = array("서울","부산","대구","광주","울산");


// 넘어온 검색어 파라미터 입니다.

$term = $_GET['term'];


// 데이터를 루핑 하면서 찾습니다.

$result = [];

foreach($cities as $city) {

    if(strpos($city, $term) !== false) {

        $result[] = array("label" => $city, "value" => $city);

    }

}


// 찾아진 데이터를 json 데이터로 변환하여 전송합니다.

echo json_encode($result);

?>



5. 하나의 입력 필드에 여러개의 값을 선택할수 있게 합니다.


콤마(,)로 분리해서 하나의 입력 필드에 여러개의 값을 선택할 수 있게 하는 방법입니다.


<script type="text/javascript">

//<![CDATA[

$(function() {

    function split( val ) {

        return val.split( /,\s*/ );

    }

    function extractLast( term ) {

        return split( term ).pop();

    }

   

    $("#city")

    // 항목을 선택할때 탭으로 이동하지 못하게 한다.

    .on("keydown", function( event ) {

        if(event.keyCode === $.ui.keyCode.TAB && $(this).autocomplete("instance").menu.active) {

            event.preventDefault();

        }

    })

    .autocomplete({

        source: function( request, response ) {

            $.getJSON( "search.php", {term: extractLast(request.term)}, response);

        },

        search: function() {

            // 최소 입력 길이를 마지막 항목으로 처리합니다.

            var term = extractLast(this.value);

            if(term.length < 2) {

                return false;

            }

        },

        focus: function() {

            return false;

        },

        select: function(event, ui) {

            var terms = split(this.value);

            // 현재 입력값 제거합니다.

            terms.pop();

            // 선택된 아이템을 추가합니다.

            terms.push(ui.item.value);

            // 끝에 콤마와 공백을 추가합니다.

            terms.push("");

            this.value = terms.join(", ");

            return false;

        }

    });

});

//]]>

</script>





6. 기존의 콤보박스에 자동완성 기능 부여하기


콤보박스를 입력가능하게 하여 자동완성 기능을 사용할 수 있도록 할 수 있습니다.




새로 생성될 위젯의 스타일을 지정합니다.


<style>

  .custom-combobox {

    position: relative;

    display: inline-block;

  }

  .custom-combobox-toggle {

    position: absolute;

    top: 0;

    bottom: 0;

    margin-left: -1px;

    padding: 0;

  }

  .custom-combobox-input {

    margin: 0;

    padding: 5px 10px;

  }

</style>


콤보박스 입니다. 여기에 자동완성 기능을 사용 가능하도록 커스텀 위젯으로 교체가 되는 것입니다.


<div class="ui-widget">

  <label for="city">도시: </label>

  <select id="city">

  <option value="서울">서울</option>

  <option value="부산">부산</option>

  <option value="대구">대구</option>

  <option value="광주">광주</option>

  <option value="울산">울산</option>

  </select>

</div>


자동완성 기능을 수행하는 커스텀 위젯을 생성하는 코드 입니다. 기능을 주석을 참조해 주세요.


<script type="text/javascript">

//<![CDATA[

$(function() {

    $.widget("custom.combobox", {

        _create: function() {

            this.wrapper = $("<span>").addClass("custom-combobox").insertAfter(this.element);

            this.element.hide();

            this._createAutocomplete();

            this._createShowAllButton();

        },

        _createAutocomplete: function() {

            var selected = this.element.children(":selected"), value = selected.val() ? selected.text() : "";

 

            this.input = $("<input>")

                .appendTo(this.wrapper)

                .val(value)

                .attr("title", "")

                .addClass("custom-combobox-input ui-widget ui-widget-content ui-state-default ui-corner-left")

                .autocomplete({

                    delay: 0,

                    minLength: 0,

                    source: $.proxy(this, "_source"),

                    // 한글 항목 커서로 선택시 오류방지

                    focus: function(event, ui) {

                        return false;

                    },

                    select: function(event, ui) {

                      // 선택했을때 처리가 여기에 옵니다.

                    }

                })

                .tooltip({

                    classes: {"ui-tooltip": "ui-state-highlight"}

                });

 

            this._on( this.input, {

                autocompleteselect: function( event, ui ) {

                    ui.item.option.selected = true;

                    this._trigger( "select", event, {item: ui.item.option});

                },

 

                autocompletechange: "_removeIfInvalid"

            });

        },

 

        _createShowAllButton: function() {

            var input = this.input, wasOpen = false;

 

            $("<a>")

                .attr("tabIndex", -1)

                .attr("title", "모두보기")

                .tooltip()

                .appendTo( this.wrapper )

                .button({

                    icons: {primary: "ui-icon-triangle-1-s"},

                    text: false

                })

                .removeClass( "ui-corner-all" )

                .addClass("custom-combobox-toggle ui-corner-right")

                .on("mousedown", function() {

                    wasOpen = input.autocomplete("widget").is(":visible");

                })

                .on("click", function() {

                    input.trigger( "focus" );

 

                    // 이미 보여지고 있다면 닫습니다.

                    if(wasOpen) {

                        return;

                    }

 

                    // 모든 결과 출력을 위해서 빈문자열을 보냅니다.

                    input.autocomplete("search", "");

                }

            );

        },

 

        _source: function(request, response) {

            var matcher = new RegExp($.ui.autocomplete.escapeRegex(request.term), "i");

            response( this.element.children("option").map(function() {

                var text = $(this).text();

                if(this.value && (!request.term || matcher.test(text))) {

                    return {

                        label: text,

                        value: text,

                        option: this

                    };

                }

            }));

        },

 

        _removeIfInvalid: function(event, ui) {

            // 아이템을 선택합니다. 아무것도 하지 않습니다.

            if(ui.item) {

                return;

            }

 

            // 일치하는것을 찾습니다. (대소문자를 구분하지 않습니다.)

            var value = this.input.val(), valueLowerCase = value.toLowerCase(), valid = false;

            this.element.children( "option" ).each(function() {

                if($(this).text().toLowerCase() === valueLowerCase) {

                    this.selected = valid = true;

                    return false;

                }

            });

 

            // 일치하는것을 찾으면 아무것도 하지 않습니다.

            if(valid) {

                return;

            }

 

            // 빈값 항목을 삭제합니다.

            this.input

                .val("")

                .attr("title", value + " 일치하는 항목이 없습니다.")

                .tooltip("open");

            this.element.val("");

            this._delay(function() {

                this.input.tooltip("close").attr("title", "");

            }, 2500);

            this.input.autocomplete("instance").term = "";

        },

 

        _destroy: function() {

            this.wrapper.remove();

            this.element.show();

        }

    });

 

    $("#city").combobox();

});

//]]>

</script>



jQuery UI autocomplete 위젯을 사용하여 자동완성 기능을 만들어 보았습니다. 자세한 기능들은 데모페이지(http://jqueryui.com/autocomplete/)와 API 문서(http://api.jqueryui.com/autocomplete/) 를 참조하시면 되겠습니다.

반응형