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

프로그래밍/자바스크립트 2018. 4. 20. 23:21
반응형

입력 필드에 타이핑을 하면 관련 정보를 보여주고 선택할 수 있는 기능이 많이 사용됩니다. 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/) 를 참조하시면 되겠습니다.

반응형

댓글을 달아 주세요

  • 늘한 2019.09.16 10:24  댓글주소  수정/삭제  댓글쓰기

    개발 공부를 하고있는 학생인데 도움이 많이 되었습니다!

  • 음음 2019.11.28 23:10  댓글주소  수정/삭제  댓글쓰기

    공유해주셔서 감사합니다
    6. 기존의 콤보박스에 자동완성 기능 부여하기 에서 ajax php경로와 response로 받는건 어디에 추가하면 되나요?

    • pentode 2019.11.29 00:23 신고  댓글주소  수정/삭제

      6. 기존 콤보박스에 자동왕성 부여하기는 콤보박스를 만드는 정보를 동적으로 서버에서 가져오는 것이 아니라, 기존의 내용을 모두 가지고 있는 콤보박스에 자동완성 기능을 추가하는 것입니다.

      이미 사용하고 있는 콤보박스에 데이터가 너무 많아서 선택하기 불편할때 서버에서 검색된 데이터를 가져오도록 하려면 변경사항이 너무 많으니까, 이미 데이터를 가지고 있는 콤보박스에 자동완성 검색기능을 추가하는 방법이라고 보시면 됩니다.

  • sunny 2020.02.07 18:25  댓글주소  수정/삭제  댓글쓰기

    안녕하세요. 제공해 주신 소스중에 "2. 기본 기능 사용하기"를
    사용하여 자동완성기능을 완성하였습니다.

    그런데 리스트로 조회 항목을 가져와서 선택을 하려고 마우스를 가져데면 리스트가 사라집니다.
    말씀하신데로 한글도 있어서
    focus: function(event, ui) {
    return false;
    //event.preventDefault();
    }
    를 했는데도 사라집니다. 무슨 이유일까요?
    답변 주신다면 너무 감사합니다.

    • pentode 2020.02.08 20:16 신고  댓글주소  수정/삭제

      안녕하세요. 위 소스에서 한글 사용시 포커스가 사라지는 것도 마우스로는 잘 동작합니다. 키보드 상하 키로 선택을 하려고 할때 문제가 되는것을 해결하는 방법 입니다.

      마우스로 선택하려는데 사라진다면 원인은 다른에 있을것 같네요. 가장 기본적인 소스 부터 확인해보세요. 페이지에 추가된 다른 무언가가 원인일 수 있습니다.

  • silvershining 2020.07.15 10:50  댓글주소  수정/삭제  댓글쓰기

    안녕하세요.
    jquery 1.21.1 버전을 사용하라고 하셨는데,
    제가 다른 기능때문에 3.4.1도 쓰고 있는데 같이 쓰니 문제가 생기는데 해결방법을 아시나요?

    • pentode 2020.11.19 14:45 신고  댓글주소  수정/삭제

      여러 버전의 jquery를 사용해서 충돌이 발생했을때 다음 URL을 참고 하세요.

      https://api.jquery.com/jQuery.noConflict/#jQuery-noConflict-removeAll

  • supertoday 2021.06.07 21:59  댓글주소  수정/삭제  댓글쓰기

    안녕하세요, 너무 좋은 기능 소개 감사합니다.
    저는 콤마로 구분된 멀티입력을 적용하였는데요.
    PC는 전혀 문제가 없고, 모바일에서 한글로 첫번째 태그 입력 후 두번째 태그 입력할 때 한글이 남는 버그가 있습니다.

    예) 입력 : 학
    목록에서 학교를 눌렀다면 아래처럼 되고,
    [ 학교, ]
    여기서 키보드 한글을 "ㅎ"을 입력한다면 아래처럼 됩니다.
    [ 학교, 학ㅎ]
    이전에 입력한 키워드가 뒤에 붙어서 함께 나오는데 이를 해결할 방법이 있을까요?