Поиск по этому блогу

четверг, 28 ноября 2013 г.

jQuery Mobile Remote AutocompleteView. Доделываем и исправляем баги.

Элемент AutoComplete - это поле ввода, в котором после ввода в него определенного количества символов появляется список возможных вариантов. Например, вводим несколько букв из названия города и появляется список возможных городов. Пример на jQuery Mobile можно посмотреть тут.
http://view.jquerymobile.com/1.3.2/dist/demos/widgets/autocomplete/

Пример со списком городов, которые еще и загружаются при помощи вызова удаленного метода здесь.
http://view.jquerymobile.com/1.3.2/dist/demos/widgets/autocomplete/autocomplete-remote.html

При добавлении такого компонента в наш проект возникли некоторые дополнительные задачи о которых я расскажу в данной статье.


Задачи

1. По нажатию на элемент списка добавлять этот элемент в поле ввода и закрывать список
2. Устранить баг с выводом пустой строки (Пустая строка выводится в том случае если введено три или более символов но совпадений не найдено)




Исходный код примеров

Посмотрим исходный код который нам дает пример на сайте jQuery Mobile

HTML

<h3>Cities worldwide</h3>
<p>After you enter <strong>at least three characters</strong> the autocomplete function will show all possible matches.</p>
<ul id="autocomplete" data-role="listview" data-inset="true" data-filter="true" data-filter-placeholder="Find a city..." data-filter-theme="d"></ul>

JavaScript

$( document ).on( "pageinit", "#myPage", function() {
    $( "#autocomplete" ).on( "listviewbeforefilter", function ( e, data ) {
        var $ul = $( this ),
            $input = $( data.input ),
            value = $input.val(),
            html = "";
        $ul.html( "" );
        if ( value && value.length > 2 ) {
            $ul.html( "<li><div class='ui-loader'><span class='ui-icon ui-icon-loading'></span></div></li>" );
            $ul.listview( "refresh" );
            $.ajax({
                url: "http://gd.geobytes.com/AutoCompleteCity",
                dataType: "jsonp",
                crossDomain: true,
                data: {
                    q: $input.val()
                }
            })
            .then( function ( response ) {
                $.each( response, function ( i, val ) {
                    html += "<li>" + val + "</li>";
                });
                $ul.html( html );
                $ul.listview( "refresh" );
                $ul.trigger( "updatelayout");
            });
        }
    });
});

CSS

.ui-listview-filter-inset {
    margin-top: 0;
}

В своем примере я поменял id элемента ul с autocomplete на fromCityAutocomplete

Задача 1. По нажатию на элемент списка добавлять этот элемент в поле ввода и закрывать список

Мы не добавляем поле вода input. Добавляется только элемент <ul>.

<ul id="fromCityAutocomplete" 
  data-role="listview" data-inset="true"
  data-filter="true" 
  data-filter-placeholder="Введите город отправки..." 
  data-filter-theme="d">
</ul>

 Остальное генерируется. Это можно проверить, если посмотреть исходный код компонента.





Мы видим что генерируется тэг form внутри него тэг div и внутри div'a уже находится input. Нам необходимо получить доступ к этому сгенерированному тэгу input. Для этого обернем наш тэг <ul> в div, которому присвоим id и с помощью jQuery будем получать первый input внутри этого div.

Вот такая структура.

<div id="fromCityInput" style="padding-bottom: 5px">
<p>Откуда</p>
<ul id="fromCityAutocomplete" data-role="listview" data-inset="true"
  data-filter="true" data-filter-placeholder="Введите город отправки..." 
  data-filter-theme="d"></ul>
</div>



Вот так мы будем получать элемент input

var d = $( "#fromCityInput input");

Теперь необходимо по нажатию на элемент списка добавлять его в поле ввода input. Для этого при создании элементов списка зададим id элементам списка

html += "<li data-theme='b' id='city" + i + "'>" + val + "</li>";

Повешаем обработчик на событие нажатия по элементу списка. В этом обработчике получим наш сгенерированный input как показано выше. Так как мы всем элементам списка задали id, то теперь в цикле нужно пробежаться по этим элементам и повешать на каждый обработчик события нажатия по этому элементу. Сначала мы вешаем обработчик нажатия при помощи метода .on('tap') потом удаляем со всех элементов при помощи .off('tap'), после этого удаляем содержимое списка при помощи $ul.html( "" );

$.each( response, function ( i, val ) {
               $(document).on('tap', "#city" + i, function (e) {
                 var d = $( "#fromCityInput input");
                 d.val(val);
                 $.each( response, function ( i, val ) {
                   $(document).off('tap', "#city" + i);
                 });
                 $ul.html( "" );
               });
 
             });

Собственно текст из списка в поле ввода устнавливается с помощью следующих строчек

var d = $( "#fromCityInput input");
d.val(val);

Задача 2. Устранить баг с выводом пустой строки (Пустая строка выводится в том случае если введено три или более символов но совпадений не найдено)


Проверим длину ответа от  сервера в случае если нет совпадений и в случае если совпадения есть. Если совпадений нет то длина равна 1, если совпадения есть то длина больше 1.


Для того чтобы не создавать пустой список будет проверять длину response.

}).then( function ( response ) {
             if (response.length != 1) {
               $.each( response, function ( i, val ) {

После добавления такой проверки при отсутствии совпадений пустая строчка выводится не будет.



Код который получился у меня в итоге

HTML


<div id="fromCityInput" style="padding-bottom: 5px">
<p>Откуда</p>
<ul id="fromCityAutocomplete" data-role="listview" data-inset="true"
  data-filter="true" data-filter-placeholder="Введите город отправки..." 
  data-filter-theme="d"></ul>
</div>

CSS

.ui-listview-filter-inset {
    margin-top: 0;
}

JavaScript
$( document ).on( "pageinit", "#myPage", function() {
    $("#fromCityAutocomplete" ).on( "listviewbeforefilter", function ( e, data ) {
      var $ul = $( this ),
      $input = $( data.input ),
      value = $input.val(),
      html = "";
      $ul.html( "" );
      if ( value && value.length > 2 ) {
        $ul.html( "<li><div class='ui-loader'>" +
            "<span class='ui-icon ui-icon-loading'></span></div></li>" );
        $ul.listview( "refresh" );
        $.ajax({
          url: "http://gd.geobytes.com/AutoCompleteCity",
          dataType: "jsonp",
          crossDomain: true,
          data: {
            q: $input.val()
          }
        }).then( function ( response ) {
             if (response.length != 1) {
               $.each( response, function ( i, val ) {
                 html += "<li data-theme='b' id='city" + i + "'>" + val + "</li>";
               });
             $ul.html( html );
             $.each( response, function ( i, val ) {
               $(document).on('tap', "#city" + i, function (e) {
                 var d = $( "#fromCityInput input");
                 d.val(val);
                 $.each( response, function ( i, val ) {
                   $(document).off('tap', "#city" + i);
                 });
                 $ul.html( "" );
               });
 
             });
 
             $ul.listview( "refresh" );
             $ul.trigger( "updatelayout");
           }
      });
    }
  });
}

Комментариев нет:

Отправить комментарий