AJAX

advertisement
AJAX
1. AJAX изнутри
2. Фреймворк JQuery
3. Формирование и разбор данных в формате XML
4. Фреймворк JForm
5. Селекторы
6. Передача данных в формате JSON
1. AJAX изнутри
AJAX – это акроним, раскрывающийся как Asynchronous JavaScript And XML и
означающий асинхронный JavaScript и XML. AJAX – это технология, включающая
сценарии JavaScript в документе HTML, которые по мере необходимости в фоновом режиме
выполняют запросы к серверу (серверным сценарием на каком либо языке webпрограммирования), и получают необходимые данные, обновляя отдельные части документа
и тем самым исключая необходимость его повторной загрузки или загрузки другого
документа.
Технология AJAX служит для создания более гибких и интерактивных web-приложений. Она
позволяет выполнять асинхронные обращения к серверу, не прерывая работы пользователя и
незаметно для него.
Составные части технологии AJAX уже реализованы во всех современных браузерах, таких
как Mozilla FireFox, Internet Explorer или Opera. Таким образом клиенту не требуется
установка дополнительных модулей для взаимодействия с сайтами, построенными с
применением технологии AJAX. В состав AJAX входят следующие компоненты:
 JavaScript – основной ингредиент AJAX, реализующий функциональность на стороне
клиента. В функциях JavaScript для манипулирования отдельными частями документа
задействуется объектная модель документа (DOM).
 Объект XMLHttpRequest (встроенный в браузер) позволяет из JavaScriptорганизовать
асинхронный доступ к серверу, благодаря чему пользователь имеет возможность
продолжать работу с документом, в то время как она выполняет некоторые действия.
Под доступом к серверу подразумеваются простые запросы HTTP на выполнение
сценариев, размещенный на сервере.
 Серверные сценарии, необходимые для обслуживания запросов поступающих из
JavaScript со стороны клиента. Эти сценарии, как правило, возвращают результаты
своей работы в формате XML.
Сценарий на стороне клиента, написанный на JavaScript, обеспечивает обращение к серверу
посредством объекта XMLHttpRequest и передает данные в виде пары имя-значение с
помощью методов GET или POST. Сценарий на стороне сервера отправляет свой ответ по
протоколу HTTP, но ответ должен иметь такой формат, который может быть разобран кодом
сценария JavaScript на стороне клиента. Традиционно используется формат XML, но можно
использовать и другой формат, даже простой текст. Наиболее популярная альтернатива XML
– JavaScript Object Notation (JSON), представление объектов в JavaScript.
Применяя AJAX необходимо помнить, что на стороне клиента JavaScript может быть
отключен, что сделает приложения AJAX нефункциональными.
Вначале рассмотрим применение объекта XMLHttpRequest. Для этого создадим простой
пример. Он состоит из HTML-формы, содержащей текстовое поле, файла сценариев
JavaScript и файла на PHP, который будет формировать ответ клиенту, зависящий от
содержимого текстового поля. Для того, чтобы отобразить ответ, не требуется повторной
загрузки HTML-страницы, даже несмотря на то, что за получением ответа необходимо
обращаться к серверу. Без помощи AJAX достигнуть такого эффекта крайне сложно, и в этом
его основное преимущество.
Приведем содержимое перечисленных файлов.
Index.html
<html xmlns='http://www.w3.org/1999/xhtml'>
<head><title>AJAX+PHP - start script</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script type='text/javascript' src=start.js></script>
</head>
<body onload='process();'>
What is your name?<input type=text id='name'>
<div id='divMessage'></div>
</body></html>
По окончании загрузки страницы запускается функция 'process() , размещенная в файле
Start.js. Ответ сервера отображается в теге <div>.
Start.js
var xmlHttp=createXmlHttpRequestObject();
function createXmlHttpRequestObject()
{
var xmlHttp;
if (window.ActiveXObject)
{
try { xmlHttp=new ActiveXObject("Microsoft XMLHTTP");
}
catch (e) {xmlHttp=false;}
if(!xmlHttp) xmlHttp= new ActiveXObject("Msxml2.XMLHTTP.5.0");
}
else
{
try {xmlHttp=new XMLHttpRequest();
}
catch (e) {xmlHttp=false; }
}
if(!xmlHttp) alert("Ошибка создания объекта XMLHttpRequest");
else { return xmlHttp;alert(xmlHttp);}
}
function process()
{
if (xmlHttp.readyState==4||xmlHttp.readyState==0)
{
name=encodeURIComponent(document.getElementById("name").value);
xmlHttp.open('GET',"start.php?name="+name,true);
xmlHttp.onreadystatechange=handleServerResponse;
xmlHttp.send(null);
}
else setTimeout('process()',1000);
}
function handleServerResponse()
{
if(xmlHttp.readyState==4)
{
if(xmlHttp.status==200)
{
helloMessage=xmlHttp.responseXML.documentElement.firstChild.data;//
documentElement;
document.getElementById("divMessage").innerHTML="<i>"+helloMessage+
"</i>";
setTimeout('process()',1000);
}
else
alert("Проблема
при
обращении
к
серверу:
"+xmlHttp.statusText);
}
return ;
}
Этот файл требует ряда комментариев, поясняющих его работу. Он содержит 3 функции:
createXmlHttpRequestObject() – для создания объекта XmlHttpRequest,
process() – для чтения содержимого текстового поля формы и отправки данных серверу,
handleServerResponse() – для получения ответа сервера, его разбора и вывода в
документ HTML. Первая функция создает объект XmlHttpRequest одним из трех методов,
в зависимости от браузера, в котором открыт документ. Вторая функция анализирует
готовность этого объекта, в случае готовности читает содержимое текстового поля формы,
формирует строку запроса к серверному сценарию с передачей ему содержимого текстового
поля, определяет метод, который будет обрабатывать ответ сервера (функция
handleServerResponse()), и отправляет асинхронный запрос серверу методом
xmlHttp.send(null). Если соединение с сервером занято, функция вызывает саму себя
через 1000 миллисекунд. Третья функция определяет наличие ответа сервера, его статус (код
ошибки, 200 означает ОК), извлекает из ответа в формате XML содержимое первого
вложенного тега, и изменяет содержимое (innerHTML) целевого тега документа, обращаясь
к нему по идентификатору (ID), а затем снова, с задержкой в 1000 миллисекунд, вызывает
функцию process().
Start.php
<?
header("Content-type: text/xml; charset=utf-8");
echo "<?xml version='1.0' encoding='utf-8' standalone='yes'?>";
echo "<response>";
$name=$_GET['name'];
$usernames=array('ANDREW','NICOLAS','DARJA','GUN');
if(in_array(strtoupper($name),$usernames))
echo "Hello, ".htmlentities($name)."!";
else if(trim($name)=='') echo "So, what is your name?";
else echo htmlentities($name). ", I don't know you!-(";
echo "</response>";
?>
Здесь формируется XML-документ в кодировке UTF-8 (рекомендуемая кодировка XMLдокументов, документы в других кодировках могут обрабатываться некорректно),
извлекается параметр запроса, и в зависимости от его значения формируется один из трех
вариантов ответа. Заметим, что данный сценарий отработает при любом обращении к нему,
как из приложения AJAX, так и из браузера. Для того, чтобы серверный сценарий
отрабатывал только запрос AJAX, рекомендуется добавить проверку клиента через
переменную CHI: if($_SERVER["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest") {
Проверить работу этого примера можно по адресу http://217.71.139.66/ajax/1/
2. Фреймворк JQuery
Непосредственное применение методов и свойств объекта XMLHttpRequest, равно как и его
создание в зависимости от текущего браузера, заметно увеличивает объем кода и затрудняет
его разработку. Инструмент (Фреймворк) QJuery существенно упрощает жизнь разработчику
приложений AJAX. Рассмотрим основные методы, реализованные в библиотеке jquery1.2.6.js. Часто для вызова jQuery методов используется сокращенный вариант, функция
$ (знак доллара).
jQuery(..).load
Начнем с самого простого - загрузка HTML кода в необходимый нам DOM элемент на
странице. Для этой цели нам подойдет метод load. Данный метод может принимать
следующие параметры:
url запрашиваемой страницы
передаваемые данные (необязательный параметр)
функция, которой будет скормлен результат (необязательный параметр)
Приведем пример JavaScript кода:
$(document).ready(function(){
// по окончанию загрузки страницы
$('#example-1').click(function(){
// вешаем на клик по элементу с id = example-1
$(this).load('ajax/example.html');
// загрузку HTML кода из файла example.html
})
});
Пример подгружаемых данных (содержимое файла example.html):
Example<br/>
Data Loaded By AJAX<br/>
Bye-Bye
jQuery.ajax
Это самый основной метод, а все последующие методы лишь обертки для метода jQuery.ajax.
У данного метода лишь один входной параметр – объект, включающий в себя все настройки
(выделены параметры, которые стоит запомнить):
async - асинхронность запроса, по умолчанию true
cache - вкл/выкл кэширование данных браузером, по умолчанию true
contentType - по умолчанию “application/x-www-form-urlencoded”
data - передаваемые данные - строка иль объект
dataFilter - фильтр для входных данных
dataType - тип данных возвращаемых в callback функцию (xml, html, script, json, text,
_default)
global - тригер - отвечает за использование глобальных AJAX Event’ов, по умолчанию true
ifModified – триггер, проверяет были ли изменения в ответе сервера, дабы не слать еще
запрос, по умолчанию false
jsonp - переустановить имя callback функции для работы с JSONP (по умолчанию
генерируется на лету)
processData - по умолчанию отправляемые данный заворачиваются в объект, и
отправляются как “application/x-www-form-urlencoded”, если надо иначе – отключаем.
scriptCharset - кодировка ( актуально для JSONP и подгрузки JavaScript).
timeout - время таймаут в миллисекундах
type - GET либо POST
url - url запрашиваемой страницы
Локальные события AJAX:
beforeSend - срабатывает перед отправкой запроса
error - если произошла ошибка
success - если ошибок не возникло
complete - срабатывает по окончанию запроса
Для организации HTTP авторизации:
username - логин
password - пароль
Пример javaScript:
$.ajax({
url: '/ajax/example.html',
// указываем URL и
dataType : "json",
// тип загружаемых данных
success: function (data, textStatus) {
// вешаем свой обработчик на функцию success
$.each(data, function(i, val) { // обрабатываем полученные данные
/* ... */
});
}
});
jQuery.get
Загружает страницу, используя для передачи данных GET запрос. Может принимать
следующие параметры:
url запрашиваемой страницы
передаваемые данные (необязательный параметр)
callback функция, которой будет скормлен результат (необязательный параметр)
тип данных возвращаемых в callback функцию (xml, html, script, json, text, _default)
Применение этого метода для решения задачи из первого примера показано ниже.
Файл index.html почти не изменился, лишь кроме своего файла сценария подключаем и
библиотеку jquery-1.2.6.js. Файл серверного сценария на PHP не изменяется вовсе. Файл
Start.js стал существенно меньше:
function process()
{
name=encodeURIComponent(document.getElementById("name").value);
$.get("start.php?name="+name,function(data)
{
helloMessage=data.documentElement.firstChild.data;
document.getElementById("divMessage").innerHTML="<i>"+helloMessage+
"</i>";
setTimeout('process()',1000);
});
return;
}
Как видим, создание объекта XMLHttpRequest и контроль его состояния реализован в
библиотеке
JQuery.
Проверить
работу
этого
примера
можно
по
адресу
http://217.71.139.66/ajax/2/
jQuery.post
Данный метод аналогичен предыдущему, лишь передаваемые данные уйдут на сервер
методом POST. Может принимать следующие параметры:
url запрашиваемой страницы
передаваемые данные (необязательный параметр)
callback функция, которой будет скормлен результат (необязательный параметр)
тип данных возвращаемых в callback функцию (xml, html, script, json, text, _default)
JavaScript:
$(document).ready(function(){
// по завершению загрузки страницы
$('#example-3').click(function(){
// вешаем на клик по элементу с id = example-3
$.post('ajax/example.xml', {}, function(xml){
// загрузку XML из файла example.xml
$('#example-3').html('');
$(xml).find('note').each(function(){
// заполняем DOM элемент данными из XML
$('#example-3').append('To:'+$(this).find('to').text() + '<br/>')
.append('From: ' + $(this).find('from').text() + '<br/>')
.append('<b>'
+ $(this).find('heading').text() + '</b><br/>')
.append(
$(this).find('body').text() + '<br/>');
});
}, 'xml');
// указываем явно тип данных
})
});
Файл example.xml:
<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
jQuery.getJSON
Загружает данные в формате JSON (удобней и быстрее нежели XML). Может принимать
следующие параметры:
url запрашиваемой страницы
передаваемые данные (необязательный параметр)
callback функция, которой будет скормлен результат (необязательный параметр)
JavaScript:
$(document).ready(function(){ // по завершению загрузки страницы
$('#example-4').click(function(){
// вешаем на клик по элементу с id = example-4
$.getJSON('ajax/example.json', {}, function(json){
// загрузку JSON данных из файла example.json
$('#example-4').html('');
// заполняем DOM элемент данными из JSON объекта
$('#example-4').append('To: '
+ json.note.to + '<br/>')
.append('From: ' + json.note.from + '<br/>')
.append('<b>'
+ json.note.heading + '</b><br/>')
.append(
json.note.body + '<br/>');
});
})
});
Файл example.json:
{
note:{
to:'Tove',
from:'Jani',
heading:'Reminder',
body:'Don\'t forget me this weekend!'
}
}
jQuery.getScript
Данная функция загружает и выполняет локальный JavaScript. Может принимать следующие
параметры:
url запрашиваемого скрипта
callback функция, которой будет скормлен результат (необязательный параметр)
JavaScript:
$(document).ready(function(){
// по завершению загрузки страницы
$('#example-5').click(function(){
// вешаем на клик по элементу с id = example-5
$.getScript('ajax/example.js', function(){
// загрузку JavaScript'а из файла example.js
testAjax(); // выполняем загруженный JavaScript
});
})
});
Файл example.js:
function testAjax() {
$('#example-5').html('Test completed'); // изменяем элемент с id =
example-5
}
Отправка Формы.
Для отправки формы посредством jQuery можно использовать любой из перечисленных
способов, а вот для удобства “сбора” данных из формы лучше использовать плагин jQuery
Form
Отправка Файлов.
Для отправки файлов посредством jQuery можно использовать плагин Ajax File Upload или
One Click Upload
Взаимодействие с PHP.
Для организации работы с PHP удобно использовать библиотеку jQuery-PHP.
3. Селекторы
Использование циклического вызова функций для передачи данных на сервер (даже если
данные еще не введены посетителем) существенно нагружает как браузер, так и сервер. Более
экономичным будет использование селекторов. Выбор элементов по Id либо ClassName
аналогичен используемому в CSS:
$('#sidebar'); // выбор элемента с id = sidebar
$('.post');
// выбор элементов с class = post
$('div#sidebar'); // выбор элемента div с id = sidebar
$('div.post'); // выбор элементов div с class = post
Можно бродить по иерархии объектов в объектной модели документа.
Простой выбор потомков:
$('div span');
// выбор всех span элементов в элементах div
Аналогичный результат так же можно, получить используя следующую конструкцию:
$('div').find('span'); // выбор всех span элементов в элементах div
Выбор только непосредственных потомков
$('div > span'); // выбор всех span элементов в элементах div,
// где span является прямым потомком div'a
Так же селекторы можно группировать:
$('div, span');
// выбор всех div и span элементов
Поиск по соседям:
$('span + img');
// выбор всех img элементов перед которыми идут span элементы
$('span ~ img');
// выбор всех img элементов после первого элемента span
$('#banner').prev(); // выбор предыдущего элемента от найденого
$('#banner').next(); // выбор следующего элемента от найденого
Выбор всех элементов, всех предков, всех потомков
$('*');
// выбор всех элементов
$('p > *');
// выбор всех потомков элементов p
$('p').children(); // -$('p').parent();
// выбор всех прямых предков элементов p
$('* > p');
// выбор всех предков элементов p (скорей всего Вам не понадобится)
$('p').parents();
// -$('p').parents('div'); // выбор всех предков элемента p, которые есть div
Фильтры
Фильтров в jQuery реализовано достаточно много, и пользоваться ими одно удовольствие:
$('div:first'); // выбираем первый div в доме
$('div:last');
// выбираем последний div в доме
$('div:not(.red)'); // выбираем div'ы у которых нету класса red
$('div:even');
// выбираем четные div'ы
$('div:odd');
// выбираем нечетные div'ы
$('div:eq(N)'); // выбираем div идущим под номером N в DOMe
$('div:gt(N)'); // выбираем div'ы, индекс которых больше чем N в DOMe
$('div:lt(N)'); // выбираем div'ы, индекс которых меньше чем N в DOMe
$(':header');
// выбо заголовоков h1, h2, h3 и т.д.
$('div:animated'); // выбор элементов с активной анимацией
Фильтры по контенту и видимости:
$('div:contains(text)'); // выбираем div'ы содержащие текст
$('div:empty');
// выбираем пустые div'ы
$('div:has(p)');
// выбираем div'ы которые содержат p
$('div.red').filter('.bold') // выбираем div'ы которые содержат класс red и класс bold
$('div:hidden');
// выбираем скрытые div'ы
$('div:visible');
// выбираем видимые div'ы
Так же есть фильтры по атрибутам:
$("div[id]");
// выбор всех div с атрибутом id
$("div[title='my']"); // выбор всех div с атрибутом title=my
$("div[title!='my']"); // выбор всех div с атрибутом title не равного my
$("div[title^='my']"); // выбор всех div с атрибутом title начинающихся с my
// <div title="myCat">,<div title="myCoffee">, <div title="my...">
$("div[title$='my']"); // выбор всех div с атрибутом title заканчивающихся на my
// <div title="itsmy">,<div title="somy">, <div title="...my">
$("div[title*='my']"); // выбор всех div с атрибутом title содержащим my
// <div title="itsmy">,<div title="myCat">, <div title="its my cat">,<div title="...my...">
так же стоит отдельно отметить следующий фильтр:
$("a[rel~='external']");
// выбор всех A с атрибутом rel, содержащим external в списке значений, разделенных
пробелом.
В результате его работы будут выбраны следующие теги:
<a href="" rel="external">link</a> — да
<a href="" rel="nofollow external">link</a> — да
<a href="" rel="external nofollow">link</a> — да
<a href="" rel="friend external follow">link</a> — да
<a href="" rel="external-link">link</a> — нет
Для работы с элементами форм есть ряд селекторов, позволяющий выбирать по типу
элемента и фильтров - enabled/disabled/selected/checked :
$(":text");
// выбор всех input элементов с типом =text
$(":radio");
// выбор всех input элементов с типом =radio
$("input:enabled"); // выбор всех включенных элементов input
$("input:checked"); // выбор всех отмеченных чекбоксов
Фильтры так же можно группировать:
$("div[name=city]:visible:has(p)");
// выбор видимого div'a с именем city, который содержит тег p
Приведем так же ряд полезных селекторов для работы с элементами форм:
$("form select[name=city] option:selected").val(); // получение выбранного(-ых) элементов в
селекте city
$("form :radio[name=some]:checked").val(); // получение выбранного значения радиобатона с
именем some
$("form :checkbox:checked"); // выбор всех выбранных чекбоксов
При работе с элементом SELECT можно порекомендовать еще несколько селекторов. Они
максимально полезны в том случае, если список формируется и обрабатывается динамически.
В нашем случае это <select name=”loadFileName”>, который заполняется динамически
результатом ajax-запроса и содержит доступные для загрузки файлы.
Итак, когда вы работаете с динамически заполняемым списком, вам нужно уметь:
1. Удалить все элементы списка
$('select[@name=mySelect] option').remove();
2. Добавить в список новый элемент
$('select[@name=mySelect]').append('<option>Новый элемент списка</option>');
К примеру, список формируется из XML данных таким образом:
$(xml).find('file').each( function(){
$('select[@name=loadFileName]').append('<option>'+$(this).find('title').text()+'</option>');
});
Схема здесь проста: мы ищем все теги <file>, обрабатываем их с помощью .each() - находим
<title></title> и загоняем текст в следующий пункт списка.
3. Сделать выделенным первый пунки списка
$('select[@name=loadFileName] option:first').attr('selected', 'yes');
4. Принудительно снять выделение с элемента списка
$('select[@name=loadFileName] option:first').removeAttr('selected');
5. Получить значение выделенного пункта из списка
Тут есть два варианта. Первый, если вы используете аттрибут <option value=”some value”>:
var file = $('select[@name=loadFileName] option:selected').val();
И второй вариант: вы не задаете value, вас интересует то, что заключено между
<option>…</option>:
var file = $('select[@name=loadFileName] option:selected').text();
Теперь переменная file содержит нужное нам значение.
6. Проверить, выбран ли какой-нибудь элемент списка
Это нужно делать обязательно, иначе в приложении могут возникнуть проблемы.
if( typeof $('select[@name=loadFileName] option:selected').text() === 'undefined' ){
alert('Ни один элемент списка не выбран');
}
7. Превратить список в “автомасштабируемый” тоесть отобразить в списке ровно столько
элементов, сколько в нем есть:
$('select[@name=loadFileName]').attr('size', $('select[@name=loadFileName] option').size());
8. Сделать недоступным для выбора отдельный элемент
$('select[@name=loadFileName] option:contains('текст элемента')').attr('disabled', 'disabled');
Разрешить выделение всех ранее недоступных элементов можно так:
$('select[@name=loadFileName] option:disabled').removeAttr('disabled');
Пример применения селекторов для динамического заполнения списка приведен в примере
следующего параграфа.
4. Формирование и разбор данных в формате XML
Ранее рассмотренные примеры получали в ответ от сервера документ XML всего с одним
тегом, однако в реальных условиях объем передаваемых данных много больше. Приведем
пример динамического создания списка по выбору значения в другом списке.
Вначале рассмотрим формирование документа XML в сценарии PHP. Это можно сделать
вручную, печатая тэги XML, а можно с помощью методов и свойств объекта DOMDocument,
доступного в PHP версий выше 5.
Пример формирования XML вручную (приведен код только для одного входного значения):
<?php
header("Content-type: text/xml; charset=utf-8");
echo "<?xml version='1.0' encoding='utf-8' standalone='yes'?>";
if($_SERVER["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest") {
if($_GET['country']==1)
{
echo "<response><cities>";
echo "<city><id>1</id><name>Алушта</name></city>";
echo "<city><id>2</id><name>Геленджик</name></city>";
echo "<city><id>3</id><name>Сочи</name></city>";
echo "</cities></response>";
} } ?>
Проверить правильность формирования документа XML можно просто открыв его в браузере.
При использовании объекта DOMDocument объем серверного кода уменьшается:
<?php
if($_SERVER["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest") {
header("Content-type: text/xml; charset=UTF-8");
$dom=new DOMDocument();
$response=$dom->createElement('response');
$dom->appendChild($response);
$cities=$dom->createElement('cities');
$response->appendChild($cities);
if($_GET['country']==1)
{
//while($row=mysql_fetch_row($query){
$id=$dom->createElement('id');
$idvalue=$dom->createTextNode('1');
$id->appendChild($idvalue);
$name=$dom->createElement('name');
$nametext=$dom->createTextNode('╨Р╨╗╤Г╤И╤В╨░');
$name->appendChild($nametext);
$city=$dom->createElement('city');
$city->appendChild($id);
$city->appendChild($name);
$cities->appendChild($city);
}
$xmlString=$dom->saveXML();
echo $xmlString;
} ?>
5. Передача данных в формате JSON
Применение метода JQuery.getJSON требует обсуждения этого формата данных и
особенностей их подготовки.
Перед тем как углубиться в детали JSON, следует понять, зачем вообще нужно тратить
усилия на изучение другого формата данных, особенно, когда вы уже освоили использование
XML и обычного текста с парами "имя/значение". В двух словах это довольно просто: чем
шире ваш выбор, тем больше вариантов решения той или иной проблемы вы можете найти, и
тем выше шанс найти не просто какое-нибудь, а наилучшее решение.
При использовании пар "имя/значение" или XML вы фактически с помощью JavaScript берёте
данные из приложения и помещаете их в соответствующий формат. При этом JavaScript в
основном работает как язык преобразования данных, извлекающий их из Web-форм и
конвертирующий в формат, удобный для отправки серверной программе.
Однако иногда JavaScript используется не только как форматирующий язык. В этом случае
данными для представления являются объекты JavaScript, а это уже не просто перемещение
информации из Web-форм в запросы. В этом случае JavaScript приходится работать больше ,
так как сначала данные надо извлечь из объектов в JavaScript, а затем преобразовать их в
пары "имя/значение" или XML. И вот тут на помощь приходит JSON: он позволяет легко
конвертировать JavaScript-объекты в данные, которые можно отправлять как часть запроса
(как синхронного, так и асинхронного).
В простейшем случае JSON позволяет преобразовывать данные, представленные в объектах
JavaScript, в строку, которую можно легко передавать от одной функции к другой или - в
случае асинхронного приложения - от Web-клиента к серверной программе. JSON также
позволяет формировать более сложные структуры, чем простые пары "имя/значение".
Например, можно представлять массивы и сложные объекты, а не только простые списки
ключей и значений.
Например, пара "имя/значение" в JSON выглядит так:{ "firstName": "Brett" }
Этот довольной простой пример на самом деле занимает немного больше места, чем при
использовании пары "имя/значение":firstName=Brett
Однако удобство JSON проявляется тогда, когда необходимо объединить несколько пар
"имя/значение" в одну строку. Во-первых, вы, по сути, можете создавать своего рода записи с
данными, содержащие несколько пар "имя/значение", вот так:{ "firstName": "Brett",
"lastName":"McLaughlin", "email": "brett@newInstance.com" }
Здесь преимущества в синтаксисе JSON по сравнению с парами "имя/значение" проявляются
ещё не так явно, но теперь данные значительно проще использовать, да и читаются они
немного легче. Например, понятно, что все три пары являются частью одной записи; на связь
элементов внутри записи указывают ограничивающие их фигурные скобки.
Если же вам нужно сформировать некий список значений, то JSON становится не только
более удобным для чтения, но и более компактным. Допустим, вы хотите создать список
людей. В XML вы столкнулись бы с большим количеством открывающих и закрывающих
тэгов, а при использовании обычных пар "имя/значение" просто преобразовали бы имена
ключей, например, к такому виду: person1-firstName.
В JSON можно просто группировать несколько записей, заключив их в фигурные
скобки:{ "people": [
{ "firstName": "Brett", "lastName":"McLaughlin", "email": "brett@newInstance.com" },
{ "firstName": "Jason", "lastName":"Hunter", "email": "jason@servlets.com" },
{ "firstName": "Elliotte", "lastName":"Harold", "email": "elharo@macfaq.com" }
]}
Здесь тоже нет ничего особо сложного. Мы просто получили одну переменную people, а ее
значением является массив, содержащий три элемента, каждый из которых - запись о
человеке, в которой указаны его имя, фамилия и адрес электронной почты. Этот пример
иллюстрирует, как можно объединять записи вместе и как с помощью фигурных скобок
можно группировать элементы в одно целое. Конечно, мы можем использовать такой же
синтаксис и для описания структуры данных, в которой каждый элемент сам является
списком:
{ "programmers": [
{ "firstName": "Brett", "lastName":"McLaughlin", "email": "brett@newInstance.com" },
{ "firstName": "Jason", "lastName":"Hunter", "email": "jason@servlets.com" },
{ "firstName": "Elliotte", "lastName":"Harold", "email": "elharo@macfaq.com" }
],
"authors": [
{ "firstName": "Isaac", "lastName": "Asimov", "genre": "science fiction" },
{ "firstName": "Tad", "lastName": "Williams", "genre": "fantasy" },
{ "firstName": "Frank", "lastName": "Peretti", "genre": "christian fiction" }
],
"musicians": [
{ "firstName": "Eric", "lastName": "Clapton", "instrument": "guitar" },
{ "firstName": "Sergei", "lastName": "Rachmaninoff", "instrument": "piano" }
]
}
Из примера хорошо видно, что можно создавать структуры данных, в которой каждый
элемент основного списка также является списком. Ещё следует отметить, что ключи в парах
"имя/значение" различны для каждого элемента основного списка (ключи пар в programmers
отличаются от ключей для authors, которые в свою очередь отличаются от ключей для
musicians). JSON полностью динамичен и позволяет изменять способ представления данных
прямо внутри JSON-структуры.
Если вы захотите сформировать эту структуру данных как-то по-другому, то вам не нужно
следовать какой-нибудь предопределённой системе ограничений по работе с JSONотформатированными данными, так как её просто-напросто нет. Таким образом, в JSON
можно не только представлять данные различными способами, но даже использовать
несколько способов представления внутри одной структуры.
JSON - это родной формат для JavaScript. Это значит, что для работы с JSON-данными в
JavaScript нам не нужен какой-нибудь специальный инструментарий (toolkit) или API.
Например, можно довольно легко создать новую JavaScript-переменную и затем
непосредственно присвоить ей строку с данными, отформатированными в JSON. Вот так:
var people =
{ "programmers": [
{ "firstName": "Brett", "lastName":"McLaughlin", "email": "brett@newInstance.com" },
{ "firstName": "Jason", "lastName":"Hunter", "email": "jason@servlets.com" },
{ "firstName": "Elliotte", "lastName":"Harold", "email": "elharo@macfaq.com" }
],
"authors": [
{ "firstName": "Isaac", "lastName": "Asimov", "genre": "science fiction" },
{ "firstName": "Tad", "lastName": "Williams", "genre": "fantasy" },
{ "firstName": "Frank", "lastName": "Peretti", "genre": "christian fiction" }
],
"musicians": [
{ "firstName": "Eric", "lastName": "Clapton", "instrument": "guitar" },
{ "firstName": "Sergei", "lastName": "Rachmaninoff", "instrument": "piano" }
]
}
Хотя это может показаться неочевидным, но эта длинная строка сверху - обычный массив, и
если вы когда-нибудь работали с массивами в JavaScript, то сможете легко получить доступ к
данным. Фактически компоненты имени массива можно разделить просто точками. Так, для
доступа к фамилии (lastname) первого элемента в списке программистов (programmers) в
JavaScript-программе можно использовать такой код:
people.programmers[0].lastName;
Заметьте, что индексация массива начинается с нуля. Доступ к искомому полю данных
осуществляется примерно так: мы начинаем с people; затем движемся к элементу
programmers и указываем, что нас интересует первая запись ([0]); наконец, мы получаем
доступ к значению по ключу lastName. В результате мы получаем строку "McLaughlin".
Пользуясь этим простым синтаксисом, можно работать с любыми структурами JSONформатированных данных, и всё это без привлечения каких-либо дополнительных
инструментариев (toolkit'ов) или API для JavaScript.
Так же как мы получили доступ к данным с помощью точек и скобок, как показано выше, мы
можем легко модифицировать данные в нашей переменной:
people.musicians[1].lastName = "Rachmaninov";
Конечно же, наши изменения были бы почти бесполезными, если бы мы не могли легко
конвертировать данные обратно в текстовый формат. К счастью, в JavaScript это также
довольно тривиальная задача:String newJSONtext = people.toJSONString();
Вероятно, ещё более важно, что мы можем конвертировать любой JavaScript-объект в JSONотформатированный текст. То есть работать таким образом можно не только с теми
переменными, которым изначально были присвоены JSON-отформатированные данные. Для
преобразования, например, объекта myObject в JSON-строку надо выполнить такую же
команду:
String myObjectInJSON = myObject.toJSONString();
В этом заключается самое большое отличие JSON от всех ранее рассмотренных форматов
данных. Пользуясь JSON, вы просто вызываете функцию и получаете ваши данные уже
отформатированными и готовыми к дальнейшему применению. При использовании же
других форматов данных форматирование возлагается на вас. Таким образом, если
необходимо работать с большим количеством объектов JavaScript, то JSON определённо
будет полезен, так как позволяет легко преобразовывать данные в формат, удобный для
отправки их в качестве запросов на сервер.
Рассмотрим в качестве примера решение предыдущей задачи автозаполнения второго списка
по выбранному значению первого списка, когда отображаемые данные представлены в
формате JSON и сохранены в отдельных файлах:
<html><head>
<meta
http-equiv='Content-Type'
content='text/html;
charset=Windows-1251'>
<script
type="text/javascript"
src="../js/jquery1.2.6.js"></script>
<script type="text/javascript">
var i=0;
jQuery(document).ready(function(){
jQuery('#country').change(function(){
value=$("select[@id=country] option:selected").val();
$('select[@name=city] option').remove();
if(value==0)
$('select[@name=city]').append('<option
value='+0+'>Здесь появятся элементы массива</option>');
jQuery.getJSON(value+'.json', {}, function(json){
var i=0;
for (i in json.city) {
$('select[@name=city]').append('<option
value='+i+'>'+ json.city[i]+'</option>');
i++;
}
});
});
});
</script>
</head><body>
<form name=myFormId method=GET action=select.php>
Страна:</div><select id="country" name="country">
<option value=0>Выбери страну:
<option value=russia >Россия
<option value=turkey>Турция
<option value=egypt>Египет
</select>
<P>Курорты:<select name="city" width=40>
<option>Здесь появятся элементы массива</option>
</select>
<P><input type=submit>
</form></body></html>
Разбор данных сводится к извлечению элементов массива и выполняется много проще, чем
при разборе данных в формате XML. Фактически, данные в формате JSON извлекаются из
соответствующих файлов. Приведем содержимое одного из них:
{ city:{
1:'Алушта',
2:'Геленджик',
3:'Сочи' } }
Работу этого примера можно посмотреть по адресу http://217.71.139.66/ajax/4/
Однако следует иметь в виду, что формат JSON предполагает передачу данных в кодировке
UTF-8. В случае других кодировок текста работоспособность сценария зависит от браузера.
Предыдыущий пример реализован в кодировке Windows-1251 и работоспособен в браузере
Opera, но не в Internet Explorer. Пример по адресу http://217.71.139.66/ajax/4a/ реализован в
кодировке UTF-8 и работоспособен в обеих браузерах.
Однако использовать готовые файлы данных (или создавать их по мере необходимости)
возможно не всегда. Рассмотрим формирование данных в формате JSON на стороне сервера:
Сценарий на стороне клиента не изменяется, а серверный сценарий выгладит так:
<?
if(isset($_REQUEST['country']))
{
if($_GET['country']==1) {
//echo
json_encode(array("1"
=>
'Алушта',
'2'
=>
"Геленджик",'3'=>'Сочи'));
echo
array_to_json(array("1"
=>
'Алушта',
'2'
=>
"Геленджик",'3'=>'Сочи')); //
}
if($_GET['country']==2) {
echo array_to_json(array("1" => 'X', '2' => "Y")); //
}
if($_GET['country']==3) {
echo
array_to_json(array("1"
=>
'А',
'2'
=>
"Б",'3'=>'В','4'=>'Г')); // И возвращаем
}
}
?>
Из примера видно, что преобразование массива в формат JSON производится одной из двух
функций: json_encode или array_to_json. Их различие в том, что первая включена в
библиотеки PHP версии 5 и выше, а вторая применяется в предыдущих версиях, но не как
библиотечная функция, а в исходном коде:
function array_to_json( $array ){
if( !is_array( $array ) ){
return false;
}
$associative
=
count(
array_diff(
array_keys($array),
array_keys( array_keys( $array )) ));
if( $associative ){
$construct = array();
foreach( $array as $key => $value ){
if( is_numeric($key) ){
$key = "key_$key";
}
$key = "'".addslashes($key)."'";
if( is_array( $value )){
$value = array_to_json( $value );
}
else
if(
!is_numeric(
$value
)
||
is_string( $value ) ){
$value = "'".addslashes($value)."'";
}
$construct[] = "$key: $value";
}
$result = "{ " . implode( ", ", $construct ) . " }";
} else { // If the array is a vector (not associative):
$construct = array();
foreach( $array as $value ){
if( is_array( $value )){
$value = array_to_json( $value );
}
else
if(
!is_numeric(
$value
)
||
is_string( $value ) ){
$value = "'".addslashes($value)."'";
}
$construct[] = $value;
}
$result = "[ " . implode( ", ", $construct ) . " ]";
}
return $result;
}
Работоспособность этого примера можно проверить по адресу http://217.71.139.66/ajax/5/
Отправка данных серверу немного сложнее.
Прежде всего, нужно четко понимать, что отправить данные в формате JSON можно в
параметрах запроса (GET или POST), т.е. точно также как и любые другие данные.
Т.к. формат JSON представляет собой обычную строку, то алгоритм отправки будет
следующим.
1) Формируем JavaScript объект с данными, которые нужно отправить, например, со
значениями, введенными пользователем в поля формы.
2) Преобразовываем этот объект в JSON формат.
3) Отправляем запрос серверу. В одном из параметров запроса передаем строку с JSON
данными.
4) На стороне сервера читаем переданные данные (они придут в массиве $_GET или $_POST).
5) С помощью json_decode преобразуем JSON данные в массив.
Теперь рассмотрим небольшой пример.
Допустим, у нас есть страница с формой, которая содержит 2 поля: field1 и field2.
Необходимо отправить эти данные в формате JSON серверному скрипту и прочитать его
ответ.
Разметку формы приводить не будем, она самая.
Сразу перейдем к JavaScript коду.
$(function() {
$("#myForm").submit(function() {
var formData = {
"field1":$("#field1").val(),
"field2":$("#field2").val()
};
$.ajax({
url:'dataparser.php'
, type:'POST'
, data:'jsonData=' + $.toJSON(formData)
, success: function(res) {alert(res); }
});
return false;
});
});
В этом примере использована библиотека jQuery и плагин jquery-json. Этот плагин
значительно упрощает преобразование данных в JSON формат, т.е. сводит всю работу к
вызову одного метода $.toJSON(...).
Рассмотрим подробнее этот пример.
Прежде всего, мы назначили обработчик события submit для формы. Обратите внимание, что
этот обработчик возвращает false. Таким образом, мы предотвращаем отправку данных
формы обычным способом. Далее мы формируем JavaScript объект и заполняем его
введенными в форму данными. Затем отправляем AJAX запрос. В параметре url указываем
название PHP скрипта, который выполняет обработку данных. В параметре type – способ
передачи данных. Третий параметр (data) самый интересный. Здесь указываем имя параметра,
в котором будут отправлены данные (jsonData), и сами данные (преобразуем JavaScript
объект в JSON строку с помощью $.toJSON).
После этого, в параметре success указываем функцию, которая будет обрабатывать
полученные данные.
В результате серверу будет отправлен только один параметр
jsonData {"field1": "111", "field2": "222"}
Теперь рассмотрим серверный скрипт.
<?php
$data = json_decode($_POST['jsonData']);
$response = 'Получено параметров '.count($data).'\n';
foreach ($data as $key=>$value) {
$response .= 'Параметр: '.$key.'; Значение: '.$value.'\n';
}
echo $response;
?>
Чтение и преобразование данных выполняется одной строчкой кода. В результате получаем
массив ($data) с данными формы. После этого скрипт формирует строку с этими же данными
и отправляет её назад браузеру.
6. Фреймворк JForm
Плагин jQuery Form позволяет не только сделать новые ajax-формы, но и довольно просто
"проапгрейдить" уже существующие формы таким образом, чтобы их можно было
использовать вместе с Ajax. Основные методы, ajaxForm и ajaxSubmit, собирают информацию
из элементов формы, поддерживают многочисленные опции, использование которых даст
полный контроль над передачей данных.
Нам потребуется подключить к странице два файла: библиотеку jQuery и файл jquery.form.js.
Сделаем это в разделе HEAD.
<script type="text/javascript" src="js/jquery-1.2.1.js"></script>
<script type="text/javascript" src="js/jquery.form.js"></script>
Затем создадим самую простейшую форму, не содержащую какой-либо специальной
разметки:
<form id="myForm" action="comment.php" method="post">
Имя: <input type="text" name="name" />
Комментарий: <textarea name="comment"></textarea>
<input type="submit" value="Комментировать" />
</form>
и добавим еще немного javascript:
<script type="text/javascript">
$(document).ready(function(){
$("#myForm").ajaxForm(function() {
alert("Спасибо за комментарий!");
});
});
</script>
Когда мы нажмем кнопку "Комментировать" значения полей name и comment будут переданы
методом POST файлу comment.php. Если сервер вернет успешный ответ (т.е. всего лишь код
200) - пользователь увидит сообщение "Спасибо за комментарий!".
Эффектнее было бы не выводить сообщение в alert(), а вставить сообщение непосредственно
в документ. Так что все, что мы здесь выиграли - избавились от перезагрузки страницы.
Выясним, в чем отличие метода ajaxForm от метода ajaxSubmit. Оба метода либо не
принимают аргументов, либо принимают один аргумент, который может быть или функцией
или объектом (в парах ключ/значение могут быть переданы различные опции).
Первое отличие состоит в том, что метод ajaxSubmit отправляет данные из формы, а метод
ajaxForm - нет. Когда вызывается метод ajaxSubmit, он упорядочивает данные формы в
строку запроса и отправляет их серверу. Когда же вызывается метод ajaxForm - он только
добавляет необходимое событие в форму таким образом, что можно определить, когда
пользователь отправил данные.
Второе отличие: при использовании ajaxForm передаваемые значения будут включать пару
имя/значение для самой кнопки (как в примере, или координаты клика мышью, если
используется картинка).
Вывод: это не значит, что метод ajaxForm - плохой, а метод ajaxSubmit - хороший. Просто они
разные. И какой именно метод использовать - надо решать в каждом конкретном случае.
Давайте теперь познакомимся с доступными опциями, которые принимают оба этих метода.
Посмотрим фрагмент кода, чтобы увидеть как задаются опции:
// готовим объект
var options = {
target: "#divToUpdate",
url: "form.php",
success: function() {
alert("Спасибо за комментарий!");
}
};
// передаем опции в ajaxSubmit
$("#myForm").ajaxSubmit(options);
target - идентифицирует тот элемент (или элементы) на странице, который должен быть
обновлен при поступлении ответа от сервера. Значение может быть определено как объект
или селектор jQuery или элемент объектной модели документа. Значение по умолчанию - null.
url - URL, куда должны быть переданы данные из формы. Значение по умолчанию значение атрибута action формы.
type - метод, с помощью которого должны быть отправлены данные из формы (GET или
POST). Значение по умолчанию - значение атрибута method формы. Если атрибут не
определен, используется метод GET.
beforeSubmit - функция, которая будет вызвана до отправки данных из формы. Функция,
вызываемая тут, может позволить выполнить какие-либо действия до отправки данных,
например проверку введенных данных. И если она возвращает false - данные не будут
отправлены на сервер. Принимает три аргумента: массив с данными формы, jQuery-объект
формы, объект из опций, определенных в ajaxForm/ajaxSubmit. Массив данных формы
принимает такой вид:
[ { name: "username", value: "Vasya" },
{ name: "password", value: "secret" } ]
Значение по умолчанию - null.
success - функция, которая будет вызвана после отправки данных серверу и при условии
успешного ответа сервера. Полученные данные - или responseText или responseXML, в
зависимости от значения опции dataType. Значение по умолчанию - null.
dataType - определяет ожидаемый тип данных в ответе сервера. Может принимать
значения: null, "xml", "script", или "json". Опция позволяет точно определить, как именно
должен быть обработан ответ сервера.
- "xml": if dataType == "xml" ответ сервера рассматривается как XML и в success (если опция
определена) отправляется значение responseXML;
- "json": if dataType == "json" ответ сервера будет выполнен и передан в success (если опция
определена);
- "script": if dataType == "script" ответ сервера будет выполнен в глобальном контексте;
Значение по умолчанию - null.
semantic - флаг, определяющий должны ли данные передаваться в строгом порядке
следования (это происходит медленнее). Упорядочивание данных формы происходит в
порядке следования элементов, исключая элементы input, имеющие тип image. Необходимо
установить эту опцию в true, если Ваш сервер требует строгого порядка следования, и форма
содержит элементы input типа image. Значение по умолчанию - false.
resetForm - флаг, определяющий должна ли форма быть сброшена если передача данных
была успешной. Значение по умолчанию - null.
clearForm - флаг, определяющий должна ли форма быть очищена если передача данных
была успешной. Значение по умолчанию - null.
Методы ajaxForm и ajaxSubmit не единственные. Давайте немного познакомимся с
остальными.
Метод formSerialize - упорядочивает данные из элементов формы в строку запроса. Метод
возвращает строку в формате: name1=value1&name2=value2.
var qString = $("#myFormId").formSerialize();
// теперь данные могут быть отправлены
// через $.get, $.post, $.ajax, и т.д.
$.post("myscript.php", qString);
Метод fieldSerialize - упорядочивает данные из элементов формы в строку запроса. Удобно
применять, когда требуется упорядочить в строку запроса только часть данных из формы.
Метод возвращает строку в формате: name1=value1&name2=value2
var qString = $("#myFormId .myFields").fieldSerialize();
Метод fieldValue - возвращает значения выбранных элементов в виде массива. С версии 0.91,
метод всегда возвращает именно массив. Если нет корректных данных, то возвращается
пустой массив, в противном случае массив содержит один или более элементов.
var value = $("#myFormId :password").fieldValue();
alert("Пароль: " + value[0]);
Метод resetForm - сбросит форму в начальное состояние через новый вызов элементов формы
из объектной модели документа.
$("#myFormId").resetForm();
Метод clearForm - очищает элементы формы. Этот метод очистит все элементы ввода с типом
text, password, textarea, очистит выбор в элементах select и снимет отметки с элементов radio и
checkbox.
$("#myFormId").clearForm();
Метод clearFields - очищает элементы формы. Удобно применять, когда требуется очистить
только часть формы.
$("#myFormId .myFields").clearFields();
Рассмотрим пример формы
<html><head>
<title>Построение интерфейсов на базе jQuery</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="js/jquery-1.2.6.js"></script>
<script type="text/javascript" src="js/jquery.form.js"></script>
</head><body>
<div id="output">AJAX-ответ от сервера заменит этот текст.</div>
<form id="myForm" action="form.php" method="post">
<input type="hidden" name="Hidden" value="hidden Value" /><br />
<label for="Name">Имя:</label>
<input name="Name" type="text" value="Моё имя" /><br />
<label for="Password">Пароль:</label>
<input name="Password" type="password" /><br />
<label for="Multiple">Мультиселект:</label>
<select name="Multiple" multiple="multiple">
<optgroup label="Группа 1">
<option value="one" selected="selected">Первый элемент</option>
<option value="two">Второй элемент</option>
<option value="three">Третий элемент</option>
</optgroup>
<optgroup label="Группа 2">
<option value="four">Четвертый элемент</option>
<option value="five">Пятый элемент</option>
<option value="six">Шестой элемент</option>
<option value="seven">Седьмой элемент</option>
</optgroup>
</select><br />
<label for="Single">Элемент select:</label>
<select name="Single">
<option value="one" selected="selected">Первый элемент</option>
<option value="two">Второй элемент</option>
<option value="three">Третий элемент</option>
</select><br />
<label for="Single2">Элемент select 2:</label>
<select name="Single2">
<optgroup label="Группа 1">
<option value="A" selected="selected">Буква A</option>
<option value="B">Буква B</option>
<option value="C">Буква C</option>
</optgroup>
<optgroup label="Группа 2">
<option value="D">Буква D</option>
<option value="E">Буква E</option>
<option value="F">Буква F</option>
<option value="G">Буква G</option>
</optgroup>
</select><br />
<label for="Check">Чекбоксы:</label>
<input type="checkbox" name="Check" value="1" />
<input type="checkbox" name="Check" value="2" />
<input type="checkbox" name="Check" value="3" /><br />
<label for="Radio">Радиобаттоны:</label>
<input type="radio" name="Radio" value="1" />
<input type="radio" name="Radio" value="2" />
<input type="radio" name="Radio" value="3" /><br />
<label for="Text">Просто текст:</label>
<textarea
name="Text"
rows="2"
cols="20">Это
элемент
textarea</textarea><br />
<input id="reset" type="reset" name="resetButton" value="Reset" />
<input
id="submit1"
type="submit"
name="submitButton"
value="Submit1" />
<input
id="submit2"
type="image"
name="submitButton"
value="Submit2" src="form.gif" />
</form>
<script type="text/javascript">
$(document).ready(function(){
var options = {
// элемент, который будет обновлен по ответу сервера
target: "#output",
beforeSubmit: showRequest,
// функция, вызываемая перед передачей
success: showResponse,
// функция, вызываемая при получении ответа
timeout: 3000 // тайм-аут
};
// привязываем событие submit к форме
$('#myForm').submit(function() {
$(this).ajaxSubmit(options);
// !!! Важно !!!
// всегда возвращаем false, чтобы предупредить стандартные
// действия браузера (переход на страницу form.php)
return false;
});
});
// вызов перед передачей данных
function showRequest(formData, jqForm, options) {
//
formData
массив;
здесь
используется
$.param
чтобы
преобразовать его в строку,
//но в самом плагине jQuery Form это совершается автоматически.
var queryString = $.param(formData);
// jqForm это jQuery объект, содержащий элементы формы.
// Для доступа к элементам формы используйте
// var formElement = jqForm[0];
alert('Вот что мы передаем: \n\n' + queryString);
// здесь можно вернуть false чтобы запретить отправку формы;
return true;
}
// вызов после получения ответа
function showResponse(responseText, statusText) {
// для обычного html ответа, первый аргумент - свойство
// responseText объекта XMLHttpRequest
// для 'xml', первый аргумент - свойство responseXML XMLHttpRequest
// для 'json', первый аргумент - объек json, возвращенный сервером.
alert('Статус ответа сервера: ' + statusText + '\n\nТекст
ответа сервера: \n' + responseText +
'\n\nЦелевой элемент div обновиться этим текстом.');
}
</script>
</body>
</html>
Работу примера можно проверить по адресу http://217.71.139.66/ajax/form.html
Но любая форма без проверки данных, вводимых пользователем - это серьезная брешь в
безопасности ресурса. Поэтому познакомимся с плагином jQuery Validation, который
позволит производить проверку вводимых данных "на лету" и, что немаловажно, очень
хорошо взаимодействует с плагином jQuery Form.
Поставим себе целью иметь некий базовый набор знаний, который поможет решить
проблемы в самых распространенных случаях. Если же понадобится что-то большее, то
подробную информацию Вы сможете найти на странице плагина jQuery Validation.
Как обычно, сначала потребуется подключить библиотеку jQuery (jQuery Validation работает
с версией 1.2.2 и выше). Понятно, что понадобится и jquery.form.js, и собственно
query.validate.js - все это подключаем в разделе HEAD нужной страницы. Можно подключить
и файл additional-methods.js, содержащий, как ясно из названия, дополнительные методы.
<script type="text/javascript" src="js/jquery-1.2.3.js"></script>
<script type="text/javascript" src="js/jquery.form.js"></script>
<script type="text/javascript" src="js/jquery.validate.js"></script>
<script type="text/javascript" src="js/additional-methods.js"></script>
HTML-код Вы сможете посмотреть в файле примера, доступного по адресу
http://217.71.139.66/ajax/validate.html. Отмечу только, что стоит следовать следующим
рекомендациям по разметке: rаждый элемент input или select имеет "свой" элемент label с
атрибутом for, значение которого одинаково со значением атрибута id соответствующего
элемента input или select. В общем, лучше на примере:
<label for="firstname">Имя</label>
<input id="firstname" name="fname" type="text" />
Теперь приведем javascript-код. Ничего особенно сложного в нем нет.
<script type="text/javascript">
$(document).ready(function(){
// готовим опции для метода
// ajaxSubmit плагина jquery.form.js
var options = {
target: "#output",
timeout: 3000 // тайм-аут
};
$("#myForm").validate({
submitHandler: function(form) {
$(form).ajaxSubmit(options);
},
focusInvalid: false,
focusCleanup: true,
rules: {
Name: {
required: true,
minlength: 2,
maxlength: 12
},
Email: {
required: true,
email: true
},
// еще настройки
// см. в исх.кодах
Examine: {
required: true,
equal: 13
}
},
messages: {
Name: {
required: "Укажите свое имя!",
minlength: "Не менее 2 символов",
maxlength: "Не более 12 символов"
},
Email: {
required: "Нужно указать email адрес",
email: "Нужен корректный email адрес!"
},
// еще настройки
// см. в исх.кодах
Examine: {
required: "Надо решить этот пример!",
equal: "Вы в школе учились?"
}
},
errorPlacement: function(error, element) {
var er = element.attr("name");
error.appendTo( element.parent()
.find("label[@for="" + er + ""]")
.find("em") );
}
});
});
</script>
Самое интересное - это основной метод - validate,
$("#myForm").validate({
// список опций
});
который может принимать просто огромное количество опций (набор пар ключ/значение) и в
соответствии с ними выполнять проверку выбранной формы. Метод validate устанавливает
обработчики событий для submit, focus, keyup, blur и click, чтобы переключиться в проверку
всей формы или ее отдельных полей.
Приведем наиболее востребованные опции с пояснениями:
submitHandler - когда форма корректно заполнена, вызывает обработчик для передачи
формы. Заменяет собой передачу формы по умолчанию. В примере используется передача
данных через метод ajaxSubmit() плагина jQuery Form.
ignore - отменяет проверку полей формы с указанным селектором. В примере ниже отменяет проверку для всех элементов с классом "ignore".
$("#myform").validate({
ignore: ".ignore"
});
rules - пары ключ/значение, описывающие правила проверки. Ключ - это значение атрибута
name элемента (или группы элементов для элементов checkbox и radio). Значение - объект
(или строка), содержащий пары правило/параметр. Правила могут быть считаны еще и из
разметки (классы, атрибуты, метаданные). Эти способы можно комбинировать между собой.
$(".selector").validate({
rules: {
// поле name - обязательное
name: "required",
// для поля email
email: {
// заполнение обязательно
required: true,
// значение д.б. корректным
email: true
}
}
});
messages - пары ключ/значение, описывающие сообщения в процессе проверки. Ключ - это
значение атрибута name элемента (или группы элементов для элементов checkbox и radio).
Значение же его будет отображено для соответствующего элемента.
$(".selector").validate({
rules: {
name: "required",
email: {
required: true,
email: true
}
},
messages: {
// если не заполнено поле name user увидит сообщение
name: "Пожалуйста, представьтесь!",
email: {
// если не заполнено поле email user увидит сообщение
required: "Нужно указать e-mail!",
// если поле email некорректно user увидит сообщение
email: "E-mail д.б. корректным!"
}
}
});
onsubmit, onfocusout, onkeyup, onclick - отвечают за инициализацию проверки
полей формы по соответствующему событию. По умолчанию все установлены в true. Любые
из этих опций можно отключить, установив значение false.
errorPlacement - в качестве значения функция, принимающая два аргумента. Первый ошибка как объект jQuery, второй - некорректный элемент как объект jQuery. С помощью
этой опции сообщение об ошибке может быть выведено в целевой элемент в разметке
страницы. Давайте разберем на примере:
errorPlacement: function(error, element) {
var er = element.attr("name");
error.appendTo( element.parent()
.find("label[@for="" + er + ""]")
.find("em") );
}
В переменную er получаем значение атрибута name элемента, в котором обнаружена ошибка.
Сообщение об ошибке добавляем куда? Правильно - в целевой элемент, который еще надо
найти. Находим "родителя" этого элемента, в нем обнаруживаем элемент label с атрибутом
for, который имеет значение точно такое же, которое у нас уже хранится в переменной er
(помните рекомендации по разметке?), находим в нем целевой элемент em. Вот туда и будет
вставлен текст сообщения об ошибке.
Методы проверки. Плагин jQuery Validation предоставляет целый набор стандартных методов
проверки.
required( ) - делает элемент обязательным для заполнения. Возвращает false, если
элемент пустой (текстовое поле), не отмечен (radio/checkbox) или ничего не выбрано (для
select).
$("#myform").validate({
// здесь field - идентификатор
// соответствующего поля ввода
rules: { field: "required" }
});
remote(url) - запрашивает ресурс, расположенный на сервере через $.ajax
(XMLHttpRequest) и передает пару ключ/значение, соответствующую атрибуту name
проверяемого элемента в GET-запросе. Ответ сервера оценивается как данные в формате
JSON и должен вернуть true для корректных данных, и false - для некорректных.
$("#myform").validate({
rules: {
email: {
required: true,
email: true,
remote: "check-email.php"
}
}
});
minlength(length) - элемент ввода будет требовать ввести количество символов не
менее, чем указано в length. Работает с текстовыми полями ввода (в т.ч. с password), c select и
checkbox.
$("#myform").validate({
rules: {
field: {
required: true,
minlength: 3
}
}
});
maxlength(length) - элемент ввода будет требовать ввести количество символов не
более, чем указано в length. Работает с текстовыми полями ввода (в т.ч. с password), c select и
checkbox.
$("#myform").validate({
rules: {
field: {
required: true,
maxlength: 4
}
}
});
rangelength(range) - элемент ввода будет требовать ввести количество символов,
соответствующее диапазону, указанному в range.
$("#myform").validate({
rules: {
field: {
required: true,
rangelength: [2, 6]
}
}
});
min(value), max(value), range(range) - смысл тот же, только фигурирует уже не
количество символов, а числа.
$("#myform").validate({
rules: {
field: {
required: true,
range: [13, 23]
}
}
});
equalTo(other) - требует, чтобы элемент соответствовал (был эквивалентен) другому
элементу, указанному в other. Возвращает true, если это условие выполняется, и false в
противном случае. Работает с текстовыми полями.
$("#myform").validate({
rules: {
password: "required",
password_again: {
equalTo: "#password"
}
}
});
email( ) - делает элемент ввода требующим корректно введенного e-mail адреса.
Возвращает true, если адрес корректный, и false в противном случае. Работает с текстовыми
полями.
$("#myform").validate({
rules: {
field: {
required: true,
email: true
}
}
});
url( ) - делает элемент ввода требующим корректно введенного URL (типа, начните с
http://). Возвращает true, если URL корректный, и false в противном случае. Работает с
текстовыми полями.
$("#myform").validate({
rules: {
field: {
required: true,
url: true
}
}
});
Download