Let’s say I have the following jQuery AJAX call:
$.ajax({
type: "POST",
url: "MyUrl",
data: "val1=test",
success: function(result){
// Do stuff
}
});
Now, when this AJAX call is made I want the server-side code to run through a few error handling checks (e.g. is the user still logged in, do they have permission to use this call, is the data valid, etc). If an error is detected, how do I bubble that error message back up to the client side?
My initial thought would be to return a JSON object with two fields: error and errorMessage. These fields would then be checked in the jQuery AJAX call:
$.ajax({
type: "POST",
url: "MyUrl",
data: "val1=test",
success: function(result){
if (result.error == "true")
{
alert("An error occurred: " & result.errorMessage);
}
else
{
// Do stuff
}
}
});
This feels a bit clunky to me, but it works. Is there a better alternative?
AJAX позволяет отправить и получить данные без перезагрузки страницы. Например, делать проверку форм, подгружать контент и т.д. А функции JQuery значительно упрощают работу.
Полное описание функции AJAX на jquery.com.
1
GET запрос
Запрос идет на index.php с параметром «text» и значением «Текст» через метод GET.
По сути это то же самое что перейти в браузере по адресу – http://site.com/index.php?text=Текст
В результате запроса index.php вернет строку «Данные приняты – Текст», которая будет выведена в сообщении alert.
$.ajax({
url: '/index.php', /* Куда пойдет запрос */
method: 'get', /* Метод передачи (post или get) */
dataType: 'html', /* Тип данных в ответе (xml, json, script, html). */
data: {text: 'Текст'}, /* Параметры передаваемые в запросе. */
success: function(data){ /* функция которая будет выполнена после успешного запроса. */
alert(data); /* В переменной data содержится ответ от index.php. */
}
});
JS
Код можно сократить используя функцию $.get
$.get('/index.php', {text: 'Текст'}, function(data){
alert(data);
});
JS
Код файла index.php
echo 'Данные приняты - ' . $_GET['text'];
PHP
GET запросы могут кэшироваться браузером или сервером, чтобы этого избежать нужно добавить в функцию параметр – cache: false.
$.ajax({
url: '/index.php',
method: 'get',
cache: false
});
JS
2
POST запросы
$.ajax({
url: '/index.php',
method: 'post',
dataType: 'html',
data: {text: 'Текст'},
success: function(data){
alert(data);
}
});
JS
Или сокращенная версия – функция $.post
$.post('/index.php', {text: 'Текст'}, function(data){
alert(data);
});
JS
Код файла index.php
echo 'Данные приняты - ' . $_POST['text'];
PHP
POST запросы ни когда не кэшироваться.
3
Отправка формы через AJAX
При отправке формы применяется функция serialize(), подробнее на jquery.com.
Она обходит форму и собирает названия и заполненные пользователем значения полей и возвращает в виде массива – {login: 'ЗНАЧЕНИЯ_ПОЛЯ', password: 'ЗНАЧЕНИЯ_ПОЛЯ'}.
Особенности serialize():
- Кнопки формы по которым был клик игнорируются, в результате функции их не будет.
- serialize можно применить только к тегу form и полям формы, т.е.
$('div.form_container').serialize();– вернет пустой результат.
Пример отправки и обработки формы:
<div class="form_container">
<div id="message"></div>
<form id="form">
<input type="text" name="login">
<input type="text" name="password">
<input type="submit" name="send" value="Отправить">
</form>
</div>
<script>
$("#form").on("submit", function(){
$.ajax({
url: '/handler.php',
method: 'post',
dataType: 'html',
data: $(this).serialize(),
success: function(data){
$('#message').html(data);
}
});
});
</script>
HTML
Код файла handler.php
if (empty($_POST['login'])) {
echo 'Укажите логин';
} elseif (empty($_POST['password'])) {
echo 'Укажите пароль';
} else {
echo 'Авторизация...';
}
PHP
4
Работа с JSON
Идеальный вариант когда нужно работать с массивами данных.
$.ajax({
url: '/json.php',
method: 'get',
dataType: 'json',
success: function(data){
alert(data.text); /* выведет "Текст" */
alert(data.error); /* выведет "Ошибка" */
}
});
JS
Короткая версия
$.getJSON('/json.php', function(data) {
alert(data.text);
alert(data.error);
});
JS
$.getJSON передает запрос только через GET.
Код файла json.php
header('Content-Type: application/json');
$result = array(
'text' => 'Текст',
'error' => 'Ошибка'
);
echo json_encode($result);
PHP
Возможные проблемы
При работе с JSON может всплыть одна ошибка – после запроса сервер отдал результат, все хорошо, но метод success не срабатывает. Причина кроется в серверной части (PHP) т.к. перед данными могут появится управляющие символы, например:

Из-за них ответ считается не валидным и считается как ошибочный запрос.
В таких случаях помогает очистка буфера вывода ob_end_clean (если он используется на сайте).
...
// Очистка буфера
ob_end_clean();
header('Content-Type: application/json');
echo json_encode($result, JSON_UNESCAPED_UNICODE);
exit();
PHP
5
Выполнение JS загруженного через AJAX
В JQuery реализована функция подгруздки кода JS через AJAX, после успешного запроса он будет сразу выполнен.
$.ajax({
method: 'get',
url: '/script.js',
dataType: "script"
});
JS
Или
$.getScript('/script.js');
JS
6
Дождаться выполнения AJAX запроса
По умолчанию в JQuery AJAX запросы выполняются асинхронно. Т.е. запрос не задерживает выполнение программы пока ждет результатов, а работает параллельно.
Простой пример:
var text = '';
$.ajax({
url: '/index.php',
method: 'get',
dataType: 'html',
success: function(data){
text = data;
}
});
alert(text); /* Переменная будет пустая. */
JS
Переменная text будет пустая, а не как ожидается текст который вернул index.php
Чтобы включить синхронный режим нужно добавить параметр async: false.
Соответственно синхронный запрос будет вешать прогрузку страницы если код выполняется в <head> страницы.
var text = '';
$.ajax({
url: '/index.php',
method: 'get',
dataType: 'html',
async: false,
success: function(data){
text = data;
}
});
alert(text); /* В переменной будет результат из index.php. */
JS
7
Отправка HTTP заголовков
Через AJAX можно отправить заголовки HEAD, они указываются в параметре headers.
$.ajax({
url: '/index.php',
method: 'get',
dataType: 'html',
headers: {'Token_value': 123},
success: function(data){
console.dir(data);
}
});
JS
В PHP они будут доступны в массиве $_SERVER, ключ массива переводится в верхний регистр с приставкой HTTP_, например:
<?php
echo $_SERVER['HTTP_TOKEN_VALUE']; // 123
PHP
8
Обработка ошибок
Через параметр error задается callback-функция, которая будет вызвана в случаи если запрашиваемый ресурс отдал 404, 500 или другой код.
$.ajax({
url: '/index.php',
method: 'get',
dataType: 'json',
success: function(data){
console.dir(data);
},
error: function (jqXHR, exception) {
if (jqXHR.status === 0) {
alert('Not connect. Verify Network.');
} else if (jqXHR.status == 404) {
alert('Requested page not found (404).');
} else if (jqXHR.status == 500) {
alert('Internal Server Error (500).');
} else if (exception === 'parsererror') {
alert('Requested JSON parse failed.');
} else if (exception === 'timeout') {
alert('Time out error.');
} else if (exception === 'abort') {
alert('Ajax request aborted.');
} else {
alert('Uncaught Error. ' + jqXHR.responseText);
}
}
});
JS
Через $.ajaxSetup можно задать обработчик ошибок для всех AJAX-запросов на сайте.
$.ajaxSetup({
error: function (jqXHR, exception) {
...
}
});
JS
This function basically generates unique random API key’s and in case if it doesn’t then pop-up dialog box with error message appears
In View Page:
<div class="form-group required">
<label class="col-sm-2 control-label" for="input-storename"><?php echo $entry_storename; ?></label>
<div class="col-sm-6">
<input type="text" class="apivalue" id="api_text" readonly name="API" value="<?php echo strtoupper(substr(md5(rand().microtime()), 0, 12)); ?>" class="form-control" />
<button type="button" class="changeKey1" value="Refresh">Re-Generate</button>
</div>
</div>
<script>
$(document).ready(function(){
$('.changeKey1').click(function(){
debugger;
$.ajax({
url :"index.php?route=account/apiaccess/regenerate",
type :'POST',
dataType: "json",
async:false,
contentType: "application/json; charset=utf-8",
success: function(data){
var result = data.sync_id.toUpperCase();
if(result){
$('#api_text').val(result);
}
debugger;
},
error: function(xhr, ajaxOptions, thrownError) {
alert(thrownError + "rn" + xhr.statusText + "rn" + xhr.responseText);
}
});
});
});
</script>
From Controller:
public function regenerate(){
$json = array();
$api_key = substr(md5(rand(0,100).microtime()), 0, 12);
$json['sync_id'] = $api_key;
$json['message'] = 'Successfully API Generated';
$this->response->addHeader('Content-Type: application/json');
$this->response->setOutput(json_encode($json));
}
The optional callback parameter specifies a callback function to run when the load() method is completed. The callback function can have different parameters:
Type: Function( jqXHR jqXHR, String textStatus, String errorThrown )
A function to be called if the request fails.
The function receives three arguments: The jqXHR (in jQuery 1.4.x, XMLHttpRequest) object, a string describing the type of error that occurred and an optional exception object, if one occurred. Possible values for the second argument (besides null) are «timeout», «error», «abort», and «parsererror». When an HTTP error occurs, errorThrown receives the textual portion of the HTTP status, such as «Not Found» or «Internal Server Error.» As of jQuery 1.5, the error setting can accept an array of functions. Each function will be called in turn. Note: This handler is not called for cross-domain script and cross-domain JSONP requests.
This function basically generates unique random API key’s and in case if it doesn’t then pop-up dialog box with error message appears
In View Page:
<div class="form-group required">
<label class="col-sm-2 control-label" for="input-storename"><?php echo $entry_storename; ?></label>
<div class="col-sm-6">
<input type="text" class="apivalue" id="api_text" readonly name="API" value="<?php echo strtoupper(substr(md5(rand().microtime()), 0, 12)); ?>" class="form-control" />
<button type="button" class="changeKey1" value="Refresh">Re-Generate</button>
</div>
</div>
<script>
$(document).ready(function(){
$('.changeKey1').click(function(){
debugger;
$.ajax({
url :"index.php?route=account/apiaccess/regenerate",
type :'POST',
dataType: "json",
async:false,
contentType: "application/json; charset=utf-8",
success: function(data){
var result = data.sync_id.toUpperCase();
if(result){
$('#api_text').val(result);
}
debugger;
},
error: function(xhr, ajaxOptions, thrownError) {
alert(thrownError + "rn" + xhr.statusText + "rn" + xhr.responseText);
}
});
});
});
</script>
From Controller:
public function regenerate(){
$json = array();
$api_key = substr(md5(rand(0,100).microtime()), 0, 12);
$json['sync_id'] = $api_key;
$json['message'] = 'Successfully API Generated';
$this->response->addHeader('Content-Type: application/json');
$this->response->setOutput(json_encode($json));
}
The optional callback parameter specifies a callback function to run when the load() method is completed. The callback function can have different parameters:
Type: Function( jqXHR jqXHR, String textStatus, String errorThrown )
A function to be called if the request fails.
The function receives three arguments: The jqXHR (in jQuery 1.4.x, XMLHttpRequest) object, a string describing the type of error that occurred and an optional exception object, if one occurred. Possible values for the second argument (besides null) are «timeout», «error», «abort», and «parsererror». When an HTTP error occurs, errorThrown receives the textual portion of the HTTP status, such as «Not Found» or «Internal Server Error.» As of jQuery 1.5, the error setting can accept an array of functions. Each function will be called in turn. Note: This handler is not called for cross-domain script and cross-domain JSONP requests.
При помощи jQuery можно значительно упростить AJAX. В данной статье рассмотрим один из вариантов.
Использовать будем $.ajax(), перед тем как писать скрипт, не забываем подключать jQuery.
Основа нашего скрипта будет выглядеть так:
$('.price-table').on('click', '.btn-item-add', function(){
$.ajax({});
return false;
});
В данном коде мы видим, что по клику на кнопку с классом .btn-item-add, у которой кстати должен быть родитель с классом .price-table, мы вызываем аякс (пока что безе параметров для более простого понимания). return false – дописываем на случай если наша кнопка сделана через тег <a>.
Теперь добавим события и базовые параметры:
//AJAX ADD TO CART
$('.price-table').on('click', '.btn-item-add', function(){
var $id = $(this).data('id'),
$thisBut = $(this),
$count = $(this).prev('.quant-block').find('.pr-item-quant').val();
$.ajax({
url: '/include/ajax_cart.php',
type: 'get',
cache: false,
data: 'id='+$id+'&count='+$count,
}).done(function(data){
//смотрим какой ответ отправляется в случае успеха
console.log(data);
}).complete(function(){
// после того как аякс выполнился
}).error(function(){
// пишем ошибку в консоль если что-то пошло не так
console.log('There was an error');
});
return false;
});
В самом начале добавились параметры, а для аякса прописали параметры: url, type, cache и data. Обратите внимание что мы передаем параметры, а в PHP $_GET в дальнейшем можно их обработать. Ссылку указываем относительно корня сайта.
Для примера у нас есть 3 jQuery события – done, complete и error. Отличие done от complete лишь в том что done вызывается первым. Таким образом мы можем в первой функции выполнить запрос, а во второй делать что душе угодно 🙂 .
Как вызвать 2 аякса подряд при помощи jQuery
Рассмотрим код посложнее. По клику у нас появляется прелоадер по середине экрана.
//AJAX ADD TO CART
$('.price-table').on('click', '.btn-item-add', function(){
$('body').append('<div class="ajax-preload"></div>');
var $id = $(this).data('id'),
$thisBut = $(this),
$count = $(this).prev('.quant-block').find('.pr-item-quant').val();
$.ajax({
url: '/include/ajax_cart.php',
type: 'get',
cache: false,
data: 'id='+$id+'&count='+$count,
}).done(function(data){
$('#bid4').html(data);
}).complete(function(){
$.ajax({
url: '/include/ajax_cart_big.php',
type: 'get',
cache: false,
data: false,
}).done(function(data){
$('#bid2').html(data);
});
$('.ajax-preload').remove();
$('body').append('<div class="tooltip">Товар добавлен в корзину</div>');
$('.tooltip').animate({ top: '20px' }, 1500).fadeOut(1500);
}).error(function(){
console.log('There was an error');
});
return false;
});
Затем наши знакомые параметры ($id, $thisBut, $count). В функции .complete записываем вызов еще одного ajax запроса. Также убираем наш прелоадер. Таким образом можно выиграть немного времени при загрузке данных.
Весь код разбирать не будем, т.к. статья и так получилась больше чем предполагалось, но я надеюсь что вы всё поняли 🙂 .
UPDATE 23.10.2018
Как передать файл через ajax:
$('#js-send-form').on('submit', function(){
if (!$(this).hasClass('normal')) {
var $dataForm = new FormData();
$dataForm.append('comment', $('#comment').val());
$dataForm.append('type', $('#types option:selected').val());
jQuery.each(jQuery('#file')[0].files, function(i, file) {
$dataForm.append('file-'+i, file);
});
$.ajax({
url: "/local/components/ready/main.documents/templates/.default/ajax_soap.php",
data: $dataForm,
cache: false,
contentType: false,
processData: false,
method: 'POST',
type: 'POST', // For jQuery < 1.9
success: function(data){
console.log(data);
}
});
return false;
}
});