Сегодня, в день релиза нового jQuery плагина для сервиса КЛАДР в облаке, я хочу показать как можно быстро сделать форму для ввода адреса с автодополнением и валидацией.
Для нетерпеливых: исходный код формы можно посмотреть на гитхабе. Для запуска примера вам достаточно скачать его в zip и открыть страницу с примером в браузере.
Несколько слов о плагине и реализованных фичах:
- Мы избавились от использования
jquery.ui.autocomplete
. Теперь плагин суммарно весит 13 Кбайт и не требует никаких дополнительных библиотек, кроме непосредственно jQuery. - Плагин теперь состоит из 2 отдельных частей: библиотеки для выполнения запросов к сервису (гитхаб) и собственно самого плагина для автодополнения (гитхаб). Это даёт возможность в случае необходимости использовать их отдельно.
- В плагине для автодополнения мы постарались реализовать весь необходимый функционал: проверку корректности введенного адреса, ajax-крутилку.
Теперь после небольшого резюме нововведений предлагаю вернуться к форме. Начнём с подключения необходимых библиотек.
<link href="../jquery.kladr.min.css" rel="stylesheet"> <link href="css/example5.css" rel="stylesheet"> <script src="js/lib/jquery-1.10.2.min.js" type="text/javascript"></script> <script src="../jquery.kladr.min.js" type="text/javascript"></script> <script src="js/example5.js" type="text/javascript"></script>
Так как целью данного поста является не стилевое оформление форм сразу приведу код html и css
HTML
<!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"> <title>Форма для ввода адреса</title> <link href="../jquery.kladr.min.css" rel="stylesheet"> <link href="css/example5.css" rel="stylesheet"> <script src="js/lib/jquery-1.10.2.min.js" type="text/javascript"></script> <script src="../jquery.kladr.min.js" type="text/javascript"></script> <script src="js/example5.js" type="text/javascript"></script> </head> <body> <form> <div class="field"> <label>Регион</label> <input type="text" name="region"> </div> <div class="field"> <label>Район</label> <input type="text" name="district"> </div> <div class="field"> <label>Город</label> <input type="text" name="city"> </div> <div class="field"> <label>Улица</label> <input type="text" name="street"> </div> <div class="field"> <label>Дом</label> <input type="text" name="building"> </div> <div class="tooltip" style="display: none;"><b></b><span></span></div> </form> </body> </html>
CSS
body, input { color: #555; font-size: 13px; font-family: Helvetica, Arial, sans-serif; } form { width: 300px; margin: 40px auto 0; padding: 20px 20px 10px; border-radius: 5px; border: 1px solid #e1e1e8; background-color: #f7f7f9; box-shadow: rgba(0,0,0,0.075) 2px 3px 7px; } input, button { outline: none; } .field label { display: inline-block; width: 80px; vertical-align: middle; } .field { margin-bottom: 10px; padding: 0; } .field input { height: 2em; min-width: 196px; border-radius: 3px; border: 1px solid #d3d3d3; box-shadow: inset 0 1px 1px rgba(0,0,0,0.1); padding: 0 7px; color: #666; } .tooltip { position: absolute; top: 16px; left: 360px; width: 220px; color: #b94a48; padding: 8px 10px; border-radius: 5px; border: 1px solid #eed3d7; background-color: #f2dede; opacity: 0.8; } .tooltip b { position: absolute; display: block; left: -14px; width: 0; height: 0; color: transparent; border: 7px solid; border-right-color: #f2dede; } #kladr_autocomplete ul { border-radius: 4px; border-color: #d3d3d3; padding: 0; background-color: #fff; } #kladr_autocomplete li { padding: 6px 8px; border: none; border-bottom: 1px solid #ededed; background-color: transparent; } #kladr_autocomplete ul .active { border: none; border-bottom: 1px solid #f0f0f0; background-color: #f0f0f0; margin-top: -1px; padding-top: 7px; } #kladr_autocomplete ul li:first-child.active { padding-top: 6px; margin-top: 0; } #kladr_autocomplete li strong { color: #5499BB; } #kladr_autocomplete .spinner { background-image: url("../img/spinner.png"); width: 16px; height: 16px; }
В итоге у нас получается вот такая вот форма.
Осталось сделать автодополнение с валидацией.
Открываем example5.js.
Сохраняем токен, ключ и объекты, которыми будем манипулировать в виде переменных.
$(function() { var token = '51dfe5d42fb2b43e3300006e'; var key = '86a2c2a06f1b2451a87d05512cc2c3edfdf41969'; var region = $('[name="region"]'); var district = $('[name="district"]'); var city = $('[name="city"]'); var street = $('[name="street"]'); var building = $('[name="building"]'); });
Теперь чтобы подключить автодополнение из сервиса, нам в простейшем варианте нужно написать следующее.
region.kladr({ token: token, key: key, type: $.kladr.type.region }); district.kladr({ token: token, key: key, type: $.kladr.type.district }); city.kladr({ token: token, key: key, type: $.kladr.type.city }); street.kladr({ token: token, key: key, type: $.kladr.type.street }); building.kladr({ token: token, key: key, type: $.kladr.type.building });
Для того чтобы автодополнение районов выполнялось из выбранного региона и т.д. задаём родительский объект для нижестоящих полей при выборе элемента в списке.
region.kladr({ select: function(obj) { region.parent().find('label').text(obj.type); district.kladr('parentType', $.kladr.type.region); district.kladr('parentId', obj.id); city.kladr('parentType', $.kladr.type.region); city.kladr('parentId', obj.id); } }); district.kladr({ select: function(obj) { district.parent().find('label').text(obj.type); city.kladr('parentType', $.kladr.type.district); city.kladr('parentId', obj.id); } }); city.kladr({ select: function(obj) { city.parent().find('label').text(obj.type); street.kladr('parentType', $.kladr.type.city); street.kladr('parentId', obj.id); building.kladr('parentType', $.kladr.type.city); building.kladr('parentId', obj.id); } }); street.kladr({ select: function(obj) { street.parent().find('label').text(obj.type); building.kladr('parentType', $.kladr.type.street); building.kladr('parentId', obj.id); } }); building.kladr({ select: function(obj) { building.parent().find('label').text(obj.type); } });
Сделаем проверку введенных данных (на случай если пользователь не будет выбирать название в списке, а введёт его вручную).
var tooltip = $('.tooltip'); var ShowError = function(input, message){ tooltip.find('span').text(message); var inputOffset = input.offset(); var inputWidth = input.outerWidth(); var inputHeight = input.outerHeight(); var tooltipHeight = tooltip.outerHeight(); tooltip.css({ left: (inputOffset.left + inputWidth + 10) + 'px', top: (inputOffset.top + (inputHeight - tooltipHeight)/2 - 1) + 'px' }); tooltip.show(); }; region.kladr({ verify: true, check: function(obj) { if(obj){ region.parent().find('label').text(obj.type); district.kladr('parentType', $.kladr.type.region); district.kladr('parentId', obj.id); city.kladr('parentType', $.kladr.type.region); city.kladr('parentId', obj.id); } else { ShowError(region, 'Неверно введено название региона'); } } }); district.kladr({ verify: true, check: function(obj) { if(obj){ district.parent().find('label').text(obj.type); city.kladr('parentType', $.kladr.type.district); city.kladr('parentId', obj.id); } else { ShowError(district, 'Неверно введено название района'); } } }); city.kladr({ verify: true, check: function(obj) { if(obj){ city.parent().find('label').text(obj.type); street.kladr('parentType', $.kladr.type.city); street.kladr('parentId', obj.id); building.kladr('parentType', $.kladr.type.city); building.kladr('parentId', obj.id); } else { ShowError(city, 'Неверно введено название населённого пункта'); } } }); street.kladr({ verify: true, check: function(obj) { if(obj){ street.parent().find('label').text(obj.type); building.kladr('parentType', $.kladr.type.street); building.kladr('parentId', obj.id); } else { ShowError(street, 'Неверно введено название улицы'); } } });
Ну и последний штрих: сделаем чтобы пункты в списке автодополнения регионов и районов форматировались в стиле «Московская обл.»
var LabelFormat = function( obj, query ){ var label = ''; var name = obj.name.toLowerCase(); query = query.toLowerCase(); var start = name.indexOf(query); start = start > 0 ? start : 0; if(query.length < obj.name.length){ label += obj.name.substr(0, start); label += '<strong>' + obj.name.substr(start, query.length) + '</strong>'; label += obj.name.substr(start+query.length, obj.name.length-query.length-start); } else { label += '<strong>' + obj.name + '</strong>'; } if(obj.typeShort){ label += ' ' + obj.typeShort + '.'; } return label; }; region.kladr({ labelFormat: LabelFormat, }); district.kladr({ labelFormat: LabelFormat, });
Вот и всё =)
Буду рад вашим вопросам и комментариям