Как сократить количество написаного кода при ajax запросах? И ассинхронная отправка файлов

Итак ajax запросы, всё просто, все привыкли их уже писать, но всё же как можно сократить количество написанного кода.
jquery.async.js

Сразу пример:
<form action="/" jasync>
	<input type="submit" />
</form>
форма отправляется ассинхронно

<input type="file" href="/" multiple jasync />
<div type="file" href="/" multiple jasync>Выберите файл</div>
<div href="/" jasync dropfile>Перетащите файлы и они отправятся на сервер</div>
файлы загружаюся асинхронно

<a href="/" jasync data="year=2013&month=5" class="send">отправить данные</a>
данные отправляется ассинхронно

И тут у многих наверное возник вопрос, как обрабатывать полученные данные, если форма не валидна зачем её отправлять, а если я хочу ещё отправить дополнительные параметры?

И начнём с вопроса как обрабатывать полученные данные
$( '.send' ).bind( 'jasync.success', function( e, data ) {
	// data - обрабатываем данные
} );

Ну это же не интересно, таким образом мы много кода не сократим. Но иногда полезно.

И тут нам поможет скрипт jquery.message.async.js, нам только нужно с сервера посылать данные в определённом формате. И атрибут jasync=«message»
<form action="/" jasync="message">
	<input type="submit" />
</form>

Пример отправляемых данных:
{
	messages: {
		{
			type: 'replace',
			elem: '#myElem',
			html: 'Заменяем новым элементом'
		},
		{
			type: 'append',
			elem: '.myClass',
			html: 'Добавляем элементы'
		},
		{
			type: 'delete',
			elem: '.delElems'
		},
		{
			callback: 'alert',
			callback_params: [ 'Заработало' ]
		},
		{
			type: 'openPopap', // Реализацию в jquery.message.ajax.js надо вам дописать, поскольку попапы обычно у всех разные
			html: '...'
		}
	}
}

или

{
	url: 'Перейи по данному адресу'
}

И так в большинстве случаев мы можем не писать ajax запросы.

Дополнительно мы можем отменять отправку, например если форма не валидна:
$( 'form' ).bind( 'jasync.beforeSend', function( ) {
	var form = $( this );
	if( !form.isValid() ) {
		form.jasync( 'stop', true ); //Отменяем отправку
	}

	// Добавить дополнительные данные при отправке и поставить тип присылаемых данных
	form.jasync( {
		'addData': {
			count: 20,
			typesend: 'send jasync'
		},
		'dataType': 'json' // Тип возвращаемых данных
	} );
} );

Код на php будет выглядеть примерно так:
header( 'Content-type: text/json' );

echo json_encode( array(
	'messages' => array(
		array(
			'type' => 'replace',
			'elem' => '#myElem',
			'html' => 'Заменяем новым элементом'
		),
		array(
			'type' => 'append',
			'elem' => '.myClass',
			'html' => 'Добавляем элементы'
		),
		array(
			'type' => 'delete',
			'elem' => '.delElems'
		),
		array(
			'callback' => 'alert',
			'callback_params' => array('Заработало')
		)
	)
) );

Попробуем его улучшить, для этого напишем дополнительный класс AsyncResponse
$message = AsyncResponse::getInstance();
$message
	->add( AsyncResponse::REPLACE, '#myElem', 'Заменяем новым элементом' )
	->add( AsyncResponse::APPEND, '.myClass', 'Добавляем элементы' )
	->add( AsyncResponse::DELETE, '.delElems' )
	->addCallback( 'console.log', 'Заработало', '!!!' );
	//->openPopup( 'Контент' )

$message->end();


Будьте аккуратны когда данные у вас отсылаются через через iframe, это происходит в случаях:

  1. Когда вы отправляете запросы на другой домен.
    Поскольку в целях безопасности мы не можете прочитать данные из другого домена загруженного в iframe,
    вам необходимо при ответе сделать редирект на ваш домен, а там уже сформировать ответ.
  2. Когда у вас загружаются изображения в старых браузерах в которых нет поддержки FormData
    Также при отправке через iframe если у вас в ответе будут теги (например div),
    у вас возникнут проблемы, браузер добавит лишние закрывающие теги и распарсить json не получится.
    В данном случае отправляйте элементарные ответы без тегов, либо перед отправкой и при приёме замените кавычки


Загрузку файлов



image
В случае Drag and Drop будет работать только в браузерах поддерживающих Drag and Drop.

Сделаем ссылку при клике на которую будет появлятся окно с выбором файлов
<a href="/image/save/" name="image" multiple jasync>Выберите файлы</a>

или блок куда надо перетащить изображение
<div href="/image/save/" name="image" dropfile jasync>Перетащите файлы</div>

Подписываемся на события загрузки каждого изображения

$( document ).on( 'jasync.beforeSend', 'a[type=file]', function( e, imgs ) {
	// Добавляем данные для отправки
	$( this ).jasync( {
		'addData': {
			count: 20
		},
		'maxSize': 20000 // Максимальный размер файлов
	} );

	if( imgs.nosupport ) {
		$( '#answer' ).html( 'Идёт загрузка через iframe, нет поддержки пред отображения...' );
		return;
	}
                
	for( var i = 0, l = imgs.length; i < l; i++ ) {
		imgs[ i ]
			// Происходит когда файл готов для отображения
			.bind( 'jasync.load', function( e, file ) {
				// file - файл в формате base64
				$( 'body' ).append( '<img src="' + file + '" />' );

 				$( this )
					// Подписываемся на события процесса загрузки
					.bind( 'jasync.uploadProgress', function( e, percent, obj ) {
						// percent - процент загрузки
					} )
					// Событие успешной загрузки
					.bind( 'jasync.success', function( e, data ) {
						//console.log( data );
					} )
					// Произошла ошибка
					.bind( 'jasync.error', function() {
						
					} );
			} );
	}

} ).on( 'jasync.success', 'a[type=file]', function( e, data ) {
	// Ловим ответ при загрузке через iframe
	$( '#answer' ).html( data );
} );


Скачать скрипты можно по адресу http://jquery-async.com/download/
Или если сервер будет не доступен, что вполне возможно, то здесь
Поделиться публикацией

Комментарии 19

    +5
    Кажется, уже у каждого есть свой jQuery плагин для асинхронной отправки форм
      0
      Больше плагинов, хороших и разных :)
        0
        Простите, но это довольно тривиально, а в данной реализации еще и небольшой минус в виде невалидных атрибутов.
        Похожих плагинов уже существует 100500.
          +1
          Возможно, я не наталкивался, скиньте ссылку
            +3
            Киньте гиперссылки хотя бы на ту пару-тройку-другую из этих 100500, что представляются Вам наилучшими.
              0
                –1
                Ну это немного не то здесь требуется в коде вызывать функцию ajaxForm и нет загрузки файлов.
                Суть данной статьи чтобы не писать js код вообще (или только в исключительных случаях), а только с сервера отправлять нужные ответы.
                  +2
                  $("form").ajaxForm(); не?
                    0
                    да это работает, т.е. так я должен подписаться на клик по элементу и вызвать функцию $(«form»).ajaxForm(); и она отправится.
                    В моём случае не надо подписываться, отправляешь ты формы, либо ты кликаешь на элементе, загружаешь файлы.

                    Я не уверен, но по моему ajaxForm не делает кросдоменные запросы
                      0
                      Вы говорите про ajaxSubmit. А ajaxForm аяксифицирует форму (формы). Насчет кроссдоменных запросов тоже не уверен.
                        0
                        Да ты прав, я про ajaxSubmit написал, ajaxForm не сработает если контент будет добавлен динамически.
                          +2
                          Окей,
                          $(document).on("submit", "form", function() { $(this).ajaxSubmit()} ));
                            0
                            Неплохой скрипт, форму отправляет.
                            Я предоставил своё виденье, постарался собрать все варианты, которые могли бы сократить код, где помимо ассинхронной отправки формы, есть отправка при клике на элемент, загрузка файлов при клике на кнопку.
                            И показал что можно сократить код, если правильно отсылать данные с сервера.
                        0
                        Оказывается умеет делать.
              0
              Метод, конечно интересный и имеет право на жизнь, но не сочтите за занудство, атрибуты «dropfile, jasync» выглядят как-то не по феншую.
              Кажется будет правильнее использовать «data-dropfile, data-jasync». Поправьте, если я ошибаюсь.
                0
                Я на самом деле думал как назвать и изначально назвал атрибут async, потом думал назвать data-async, ещё думал название поместить в глобальную переменную.
                Но я остановился на jasync, хоть это и не валидно.
                Если скрипт будет полезен, то перенесу название в глобальную переменную, чтобы ни у кого не возникали вопросы.
                0
                А мне идея понравилась, я обеими руками за декларативность там, где это возможно.
                Но вот реализация…

                Взять хотя бы имена событий с точкой, что противоречит идеолгоии событий в jQ — там точки призваны отделять event name от namespaces, а у вас obj.trigger( 'jasync.uploadProgress', ...) — не по феншую — лучше было б дефисы использовать тогда.

                И довольно странно смотрятся рядом нативное создание XMLHttpRequest и вот это $( '<div></div>' ).

                Я это к чему, выложите на GitHub, организуйте приём пулреквестов и, возможно, выйдет довольно хорошая библиотека как по идее, так и по реализации.
                  0
                  obj.trigger( 'jasync.uploadProgress', ...)
                  jasync — namespaces
                  uploadProgress — события

                  $.ajax — мне не подошёл. Был вынужден использовать XMLHttpRequest
                    –1
                    На счёт выложите на GitHub, скрипт свободно распространяется, можете дорабатывать и вылаживать где угодно, без ссылок на мой скрипт и подобной ерунды.

                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                  Самое читаемое