Сегодня, в день релиза нового 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
<!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>
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,
});
Вот и всё =)
Буду рад вашим вопросам и комментариям
$(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"]');
var tooltip = $('.tooltip');
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;
};
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({
token: token,
key: key,
type: $.kladr.type.region,
labelFormat: LabelFormat,
verify: true,
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);
},
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({
token: token,
key: key,
type: $.kladr.type.district,
labelFormat: LabelFormat,
verify: true,
select: function(obj) {
district.parent().find('label').text(obj.type);
city.kladr('parentType', $.kladr.type.district);
city.kladr('parentId', obj.id);
},
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({
token: token,
key: key,
type: $.kladr.type.city,
verify: true,
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);
},
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({
token: token,
key: key,
type: $.kladr.type.street,
select: function(obj) {
street.parent().find('label').text(obj.type);
building.kladr('parentType', $.kladr.type.street);
building.kladr('parentId', obj.id);
},
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, 'Неверно введено название улицы');
}
}
});
building.kladr({
token: token,
key: key,
type: $.kladr.type.building,
select: function(obj) {
building.parent().find('label').text(obj.type);
}
});
});
Автор: xescoder