Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > PHP: Общие вопросы > PHP + AJAX Передача данных петодом POST


Автор: nepster 20.4.2013, 03:08
Собственно вопрос такой, для работы с отправкой пост данных работаю с AJAX (jQUERY).

Код
    // НОВОСТИ
    function newsCpanel(csrfToken,action,obj_id)
    {
        if(action == 'addNews')
        {
            var data = 
            {
                "YII_CSRF_TOKEN":   encodeURIComponent(csrfToken),
                "action":           encodeURIComponent(action),
                "news_name":        encodeURIComponent(jQuery("input[name=news_name]").val()),
                "news_category":    encodeURIComponent(jQuery("select[name=news_category]").val()),
                "news_user_id":     encodeURIComponent(jQuery("input[name=news_user_id]").val()),
                "news_title":       encodeURIComponent(jQuery("input[name=news_title]").val()),
                "news_description": encodeURIComponent(jQuery("input[name=news_description]").val()),
                "news_keywords":    encodeURIComponent(jQuery("input[name=news_keywords]").val()),
                "news_status":      encodeURIComponent(jQuery("select[name=news_status]").val()),
                "news_short":       encodeURIComponent(CKEDITOR.instances.news_short.getData()),
                "news_full":        encodeURIComponent(CKEDITOR.instances.news_full.getData())
            };   
        }
        else if(action == 'editNews')
        {
            var data = 
            {
                "YII_CSRF_TOKEN":   encodeURIComponent(csrfToken),
                "action":           encodeURIComponent(action),
                "obj_id":           encodeURIComponent(obj_id),
                "news_name":        encodeURIComponent(jQuery("input[name=news_name]").val()),
                "news_category":    encodeURIComponent(jQuery("select[name=news_category]").val()),
                "news_user_id":     encodeURIComponent(jQuery("input[name=news_user_id]").val()),
                "news_date":        encodeURIComponent(jQuery("input[name=news_date]").val()),
                "news_title":       encodeURIComponent(jQuery("input[name=news_title]").val()),
                "news_description": encodeURIComponent(jQuery("input[name=news_description]").val()),
                "news_keywords":    encodeURIComponent(jQuery("input[name=news_keywords]").val()),
                "news_status":      encodeURIComponent(jQuery("select[name=news_status]").val()),
                "news_short":       encodeURIComponent(CKEDITOR.instances.news_short.getData()),
                "news_full":        encodeURIComponent(CKEDITOR.instances.news_full.getData())
            };      
        }
        else if(action == 'deleteNews')
        {
            var data = 
            {
                "YII_CSRF_TOKEN": encodeURIComponent(csrfToken),
                "action":    encodeURIComponent(action),
                "obj_id":   encodeURIComponent(obj_id)
            };      
        }
        else
        {
            return false;
        }
        
        
        // id для загрузки 
        var doom_id_load  = '.loader';
        // id для отображения ошибки
        var doom_id_error = '#loader';

        var request = jQuery.ajax({
            url: "/cpanel/news/control/",
            type: "POST",
            data: data,
            dataType: "JSON",
            
            // ЗАГРУЗКА
            beforeSend: function() { AJAXloadB(doom_id_load, true) },
            
            // ОБРАБОТКА AJAX ОШИБОК
            error:  function(xhr, str){ AJAXerror(xhr, str, doom_id_error);  AJAXloadB(doom_id_load, false) },
            
            // ЗАПРОС ПРОШЕЛ
            success: function(data)
            {
                AJAXloadB(doom_id_load, false)
                
                if(data.status == 1)
                {
                    // AJAX ОБНОВЛЕНИЕ КОНТЕНТА (если сервер возвращает content=reload)
                    // перезагрузим контент средствами AJAX
                    if(data.content == 'reload') ajaxContent(csrfToken,'news',action,doom_id_load);
                    /*****************************************************************/  
                }
                else
                {
                    switch(data.error)
                    {
                        case 'news_title>200':
                            jQuery(doom_id_error).html('ОШИБКА: поле "Заголовок" не может быть больше 200 символов').css({'color':'red'});
                        break;
                        case 'news_keywords>200':
                            jQuery(doom_id_error).html('ОШИБКА: поле "Ключевые слова" не может быть больше 200 символов').css({'color':'red'});
                        break;
                        case 'news_description>200':
                            jQuery(doom_id_error).html('ОШИБКА: поле "Описание" не может быть больше 200 символов').css({'color':'red'});
                        break;
                        case 'news_name>200':
                            jQuery(doom_id_error).html('ОШИБКА: поле "Название новости" не может быть больше 200 символов').css({'color':'red'});
                        break;
                        case 'category_id!is_numeric':
                            jQuery(doom_id_error).html('ОШИБКА: поле "Категория новости" должно быть числом').css({'color':'red'});
                        break;
                        case 'news_user_id!is_numeric':
                            jQuery(doom_id_error).html('ОШИБКА: поле "ID юзера" должно быть числом').css({'color':'red'});
                        break;
                        case 'news_status!is_numeric':
                            jQuery(doom_id_error).html('ОШИБКА: поле "Статус новости" должно быть числом').css({'color':'red'});
                        break;
                        case 'NOT_SAVED':
                            jQuery(doom_id_error).html('ОШИБКА: новость не сохранилась. Обратитесь к администратору!').css({'color':'red'});
                        break;
                        case 'THERE_IS_NO_NEWS':
                            jQuery(doom_id_error).html('ОШИБКА: новость не найдена. Обновите страницу').css({'color':'red'});
                        break;
                        case 'NEWS_ID_NAN':
                            jQuery(doom_id_error).html('ОШИБКА: Неверный формат ID новости').css({'color':'red'});
                        break;
                        default:
                            jQuery(doom_id_error).html('Возникла неизвестная ошибка').css({'color':'red'});
                    }
                }
            }
        });
    }


Все работает отлично. Только заметил одну не большую деталь. Если быстро нажимать (кучу раз тыкать по клавишам) на кнопку сохранить пока идет загрузка данных, данные будут дублироваться. 

Выглядит это так. Я нажима на сохранить, начинают грузится данные и не дожидаясь ответа от сервера я нажимаю еще кучу раз и в базу появляются дубликаты. Вместо 1 новости, я получаю 2 - 3 одинаковые. 

Подскажите пожалуйста как лучше всего бороться с такими ситуациям? 
Можно ли сделать так. что мы отправили запрос на сервер и пока сервер не ответит нельзя послать или игнорировать другой запрос от этой функции ? 

Автор: ksnk 20.4.2013, 07:32
Вариантов решения много.

На клиенте можно делать кнопке отправке "disabled" до получения данных или по таймауту. Это спасет от "дрожащих рук" нормального клиента. Рисовать окошко "форма отправляется, просим не суетится...". Красивенько, разумно, требует javascript.

На сервере, при генерации формы можно вставлять уникальное значение в скрытое поле. Каждый новый вывод формы клиенту вызовет генерацию нового значения. Это значение будет ключём для вставляемых записей. При получении данных проверяем, что эта форма ещё не пОстилась. Иначе - заменяем запись вместо вставки. Таким образом, одна форма, несколько раз подряд отправленная, вызовет только одно изменение. Если у клиента медленный (глючный, пропадающий) интернет и он успел перечитать свое сообщение исправить и послать его еще много  раз, то последнее исправление не пропадет ;)
Некоторый дискомфорт в этом решении вызывает добавление еще одного ключа в базу. Можно хранить эти ключики не в базе а в memcache или в отдельной таблице, которую подчищать со временем...

Автор: Sanchezzz 20.4.2013, 14:59
Ужас...
encodeURIComponent не обязательно использовать для $.ajax
Switch error можно упросить если обрабатывать это циклом 
Код

$.each(m.error, function(key,item){});
  
И да решение вашей проблемы 
Код

.click(function(){
 var _this = $(this);
 if(!_this.hasClass('disable')){
   _this.addClass('disable');
   $.ajax({
     success:function(m){
      // Удачно  
        _this.removeClass('disable');
     },
     error:function(){
      _this.removeClass('disable');
     }
     //...
   });

 } 
});


По рекламирую полезную штуку для сбора данных с http://ru.vingrad.com/%D0%97%D0%B0%D0%BC%D0%B5%D0%BD%D0%B0-form2Js-%D0%B2-%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D1%83-%D1%81%D0%BE%D0%B1%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%BE%D0%B3%D0%BE-%D0%B2%D0%B5%D0%BB%D0%BE%D1%81%D0%B8%D0%BF%D0%B5%D0%B4%D0%B0--id516302d96ccc19d409000650.  


Автор: nepster 21.4.2013, 22:21
большое спасибо, как раз недавно задумался об этом деле. 

Но буду еще более хитрожопие, воспользуюсь:

Код

serializeArray()





Код

    $(".AJAX_POST").submit( function(evt) {
    
        // останавливаем поведение браузера по умолчанию для submit
        evt.preventDefault();
        
        // объект формы 
        var FormObj = $(this);
        // загрузщик
        var LOADER_CLASS   = ".loader";
        // загрузщик
        var RESPONSE_CLASS = ".response";
        
        $.ajax({

            // action из формы
            url:  FormObj.attr('action'),
            
            // метод отправки данных из формы
            type: FormObj.attr('method'),
            
            // все данные формы
            data: FormObj.serializeArray(),
            
            // ответ от сервера 
            dataType: "JSON",
            
            //старт запроса
            beforeSend : function()
            {
                // заблокировать кнопку 
                FormObj.find("input[type=submit]").attr('disabled', 'disabled');
                // загрузка
                FormObj.find($(LOADER_CLASS)).show();  
            },
            
            // ОБРАБОТКА AJAX ОШИБОК
            error:  function(data,codeError)
            {
                if(codeError == 'parsererror')
                    FormObj.find(RESPONSE_CLASS).html('Возникла ошибка при получении данных с сервера! ('+codeError+')').css({'color':'red'});
                else 
                    FormObj.find(RESPONSE_CLASS).html('Сервер не отвечает! Код ошибки: '+data.status).css({'color':'red'});
            },
           
            // ЗАПРОС ПРОШЕЛ
            success:  function(data,codeError) 
            {
                if(codeError == 'success')
                {
                    var action = FormObj.serializeSearch('action');
                    switch(action)
                    {
                        // НОВОСТИ 
                        case 'addNews':
                        case 'editNews':
                        case 'deleteNews':
                            // AJAX ОБНОВЛЕНИЕ КОНТЕНТА (если сервер возвращает content=reload)
                            // перезагрузим контент средствами AJAX
                            if(data.content == 'reload') ajaxContent(FormObj.serializeSearch('csrfToken'),action,LOADER_CLASS);
                            /*****************************************************************/ 
                            newsCpanel(FormObj,data,RESPONSE_CLASS);
                        break;
                        .................
                    }          
                      
                }
                else
                {
                    FormObj.find(RESPONSE_CLASS).html('Возникла ошибка при получении данных с сервера! ('+(codeError)+')').css({'color':'red'});
                } 
            },
    
            //завершение запроса
            complete : function()
            {        
                // разблокировать кнопку 
                //FormObj.find("input[type=submit]").removeAttr('disabled');
                // выключить загрузку 
                FormObj.find($(LOADER_CLASS)).hide();
            }
        });  
            
    }); 



от свича в обработке ошибок не хотел бы отходить, очень удоьно и четебельно выглядит оформление всех ошибок 

Автор: Sanchezzz 21.4.2013, 23:03
Если мне память не изменяет то Ckeditor в массив не входит его отдельно надо запихать надо.
Пробывал  я serializeArray 1 Мне не подошел так как не умет работать с указанного элемента только с формы, а это печально и прискорбно.  2 Возвращает массив  вида { name: 'имя поля' , value:'значение'} тоже не подходит для меня.

 

Автор: nepster 22.4.2013, 12:29
хм, я еще не разбирал serializeArray() + Ckeditor, но стало интересно. 

При том же коде, вот результат

Автор: Sanchezzz 22.4.2013, 13:50
Скажу вам повезло, у меня получалось вот такой случай при отправке textarea пустое поле, возможно Ckeditor при submit формы  вставляет в textarea данные либо у меня была старая версия)

Автор: nepster 22.4.2013, 16:34
ну да, интересно если просто обычным постом кидать, в любом случае он бросает содержимое textarea на сервер. 

Тоесть если бы в вашей старой версии была просто отправка данных методом пост, то данные бы не долетели ? 
Думаю просто где-то ошиблись. 

Вроде очень удобная вещь 
Код

serializeArray()


только вот достать данные не удобно. Даже вроде нет возможности как я понял, пришлось писать функцию:

Код

$.fn.serializeSearch = function(action)
{
    var r = false;
    var a = this.serializeArray();
    $.each(a, function() {
        
        if(action !== undefined && action == this.name)
        {
            r =  this.value;
        }
    });
    return r;
};




Код

serializeSearch('action'); // вернет value (name="action")

Автор: Sanchezzz 22.4.2013, 17:32
Цитата

Тоесть если бы в вашей старой версии была просто отправка данных методом пост, то данные бы не долетели ? 
Как рас самое интересное что долетали, а вот просто обратится к textarea.val() я получал пустую строку=)
Я лучше останусь при своем костыле по причине 2) которую я писал пару постов выше.

Автор: nepster 22.4.2013, 18:16
Код

а вот просто обратится к textarea.val() я получал пустую строку=)


тут все рпавильно, эти визуалки работают по средствам iframe, тоесть он вставляется в textarea и создает такой эффект редактирования. 
Но при поссылке данных постом получаем именно данные какие нужно. 


всмсле, что нельзя данные добавлять? 
Код

<input type="hiden" name="test" value="Тестовые данные" />


и в целях навясчивости удобнее, тоесть если у пользователя отключен JS , что бы летели просто данные. Я так вставил к примеру csrfToken

Автор: Sanchezzz 22.4.2013, 18:49
Таких людей очень маленькое количество. Если нужна совместимость то я реализую такой же метод как и у вас тут вы без условно вы правы.  smile 


Автор: seregadgl 22.3.2017, 16:59
Скажу вам повезло, у меня получалось вот такой случай при отправке http://qsn.by пустое поле, возможно Ckeditor при submit формы  вставляет в textarea данные либо у меня была старая версия) 

Автор: _zorn_ 23.3.2017, 17:56
Цитата
Дата 23.4.2013

Цитата(seregadgl @  22.3.2017,  23:59 Найти цитируемый пост)
Скажу вам повезло

Только хотел написать и перешел по ссылке. Тфутымля, опять эти дизайнеры интерьеров. 
Ребята это же АНТИреклама. Я вот как увижу ваш сайт у кого нибудь, В ПЕРВУЮ ОЧЕРЕДЬ отговаривать буду. Чтобы вообще не связывались.
Хоть и делаете потолки вы возможно не плохо...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)