При копировании материалов, ссылка на источник ОБЯЗАТЕЛЬНА!!!

вторник, 6 ноября 2012 г.

Получение данных из БД без перезагрузки страницы с помощью AJAX

Многим пользователям интернета очень нравится, когда можно применить какой-то фильтр на странице, или подгрузить данные из базы данных без перезагрузки страницы. В данном посте я расскажу, как такое можно сделать с помощью JavaScript и AJAX.

Чтобы не сильно мудрить, я взял за пример случай, когда нужно получить новости определенных категорий на указанную дату. Идея такая: мы отмечаем чекбоксы нужных категорий, указываем дату и нажимаем кнопку «Показать новости»; после этого появляется картинка загрузки и данные загружаются в нужный блок страницы.

Представим ситуацию, когда у нас есть две таблицы (категории и новости) такой структуры:

Схема таблиц БД

Одно условие, что у новости может быть только одна категория (связь 1 ко ∞), в противном случае – тут уже совсем другая связь. Представим, что в наших таблицах содержатся такие данные:

categories
5 Спорт
8 Музыка
9 Кино
11 IT

news
3 Название новости 1 Текст новости 1 2012-11-03 5
4 Название новости 2 Текст новости 2 2012-11-03 9
6 Название новости 3 Текст новости 3 2012-11-03 11
7 Название новости 4 Текст новости 4 2012-11-04 5
8 Название новости 5 Текст новости 5 2012-11-04 11
10 Название новости 6 Текст новости 6 2012-11-05 8
11 Название новости 7 Текст новости 7 2012-11-05 11

Как выше указывалось, наши категории будут checkbox-ами, значит, их вывод сделаем примерно таким:
<?php
$result = mysql_query("SELECT * FROM categories ORDER BY name;")
 or die("Invalid query: " . mysql_error());

echo "<fieldset><legend>Категории</legend>";

while ($row = mysql_fetch_array($result)) {
   echo "<input name='news_cat' type='checkbox' value='".$row["id"]."' />".$row["name"]."<br/>";
}

echo "</fieldset>";
?>
Не трудно заметить, что значениями value наших чекбоксов являются идентификаторы категорий.

Кроме этого у нас указывается дата для получения новостей, и нужна сама кнопка «Показать новости». Во время получения новостей я буду отображать некий индикатор загрузки, для примера я взял такую картинку:

Картинка загрузки скрипта

Зачем это надо?! Ну если, например, у вас очень медленный хостинг, или слишком сложный запрос, который долго отрабатывается, тогда надо как-то сообщить пользователю что что-то делается. Чтобы он не нажал кнопку, увидел, что ничего не срабатывает и не ушел со страницы.

Конечно же, наш результат надо куда-то выводить, так что добавим еще и результирующий блок. Будет это, примерно, такой код:
...

Дата: <input name="newsdate" type="text" size="10" /> <span style="font-size:12px;">(yyyy-mm-dd)</span><br /><br />

<?php
$result = mysql_query("SELECT * FROM categories ORDER BY name;")
 or die("Invalid query: " . mysql_error());
    
echo "<fieldset><legend>Категории</legend>"; 

while ($row = mysql_fetch_array($result)) {
   echo "<input name='news_cat' type='checkbox' value='".$row["id"]."' />".$row["name"]."<br/>";
}

echo "</fieldset>";
?>

<br/>
<input name="getnews" type="button" value="Показать новости" onclick="getnews()" />

<div id="download_img" style="display:none;"><img src="loading.gif" alt="" width="100" height="100" /></div>
<div id="result_div"></div>

...
Если разместить данный код, то должна получится, примерно, такая картина:


Дата: (yyyy-mm-dd)

Категории IT
Кино
Музыка
Спорт




Для подгрузки результата в блок нужен такой JavaScript-код (действия в комментариях):
function getnews() {

     dateformat = /[0-9]{4}-(0[1-9]|1[012])-(0[1-9]|1[0-9]|2[0-9]|3[01])$/;
     newsdate = $('input[name="newsdate"]').val();

     // Проверяем формат введенной даты
     if (!dateformat.test(newsdate)) {
          alert("Неверный формат даты!"); 
          return false;
     }

     // Проверяем отмечен ли хоть один чекбокс 
     if ($('input[name="news_cat"]').is(':checked')==false) {
          alert("Ни одна категория не выбрана!"); 
          return false;
     }

     //Показываем картинку загрузки
     $('div#download_img').css('display', 'block');

     tagsArray = new Array();

     //Формируем массив из изначений value чекбоксов 
     $('input[name="news_cat"]:checked').each(function() {tagsArray.push(this.value);}); 

     //Отправляем ajax-запрос к файлу newsfilter.php, в нем передаем дату и массив категорий 
     $.ajax({
          type:"POST",
          url:"newsfilter.php",
          data: {"newsdate":newsdate, "categories[]":tagsArray},
          cache: false,
          success: function(responce){ 

               //Загружаем результат в блок с id=result_div и прячем картинку загрузки
               $('div#result_div').html(responce);
               $('div#download_img').css('display', 'none');
          }
      })
}
Ну и, чтобы все это дело заработало, надо создать файл newsfilter.php, который будет формировать список новостей. Различные проверки на передаваемые параметры не пишу, а также не пишу подключение к БД (думаю, несложно будет доработать код под себя), напишу только простенькую защиту от SQL-инъекций и основной функционал данного файла. Выводимую информацию также доработаете сами: всякие там стили, картинки и т.д. Я же выведу результат по-простому:
...

<?php
$newsdate = preg_replace("/[^0-9\-]/i", "", $_POST["newsdate"]);
$categories = preg_replace("/[^0-9,]/i", "", implode(",", $_POST["categories"]));

$queryText = "SELECT
                  news.title AS title,
                  news.news_text AS news_text,
                  categories.name AS categ
              FROM
                  news
              LEFT JOIN
                  categories
              ON
                  news.category = categories.id
              WHERE
                  news.category IN (".$categories.")
              AND
                  news.news_date = '".$newsdate."'
              ORDER BY
                  categories.name";
                      
$result = mysql_query($queryText);

if (mysql_num_rows($result)>0) {
     $resultText ="";
     
     while ($row = mysql_fetch_array($result)) {
          $resultText .= "<h3>".$row["title"]."</h3>";
          $resultText .= "<span style='font-style:italic;'>Категория: </span>".$row["categ"]."<br/>";
          $resultText .= "<p>".$row["news_text"]."</p>";
     }
     echo $resultText;
} else {
     echo "Нет новостей по указанным критериям!";
}
?>
Вот так можно реализовать получение данных из БД без перезагрузки страницы. Извините, что демо не могу предоставить, но, думаю, трудностей возникнуть не должно. Между тегами <head> не забудьте подключить библиотеку jQuery, чтобы работал JavaScript:
<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.js'></script>

10 комментариев:

  1. newsfilter.php

    ВОТ ПРАВИЛЬНЫЙ ВАРИАНТ ТВОЙ КОТ НЕ РАБОТАЕТ

    $newsdate = preg_replace("/[^0-9\-]/i", "", $_POST["newsdate"]);
    $categories = preg_replace("/[^0-9\-]/i", "", $_POST["categories"]);
    $string = join(',', $categories);
    $result = mysql_query ("SELECT title,news_text, news_date FROM news WHERE category IN($string) AND news_date ='$newsdate'" );
    $row = mysql_fetch_array ($result);

    if($row == false)
    {echo "Не чего не нашлось";}

    do{
    echo "
    $row[news_text]
    ";

    }
    while($row = mysql_fetch_array ($result));

    ОтветитьУдалить
    Ответы
    1. Ну не знаю, спорить не буду... Свой код я тестировал на локале в денвере, Ваш же, по-моему, отличается только использованием join (у меня implode) и конструкцией цикла... что, как на меня, не должно ничего менять...
      Посмотрим, может еще кто оставит комментарий, что данный код не работает. Пока Вы первый, кто об этом написал

      Удалить
  2. Супер, спасибо большое, получилось.
    Правда я сделал не чекбоксами, а выпадающим списком, но это не суть.
    А не подскажете, как сделать еще чекбокс, который выдавал бы новости из любой категории, т.е. value должен включать в себя id всех категорий.

    ОтветитьУдалить
    Ответы
    1. ...новости из любой категории...
      Случайной категории, или со всех категорий вместе взятых?

      Удалить
    2. Не обязательно впихивать в value все id категорий. Можно сделать его равным true или false (либо 1 и 0), и передавать его в файл newsfilter.php

      А там уже проверять... Если, например, значение 1, то убирать из запроса условие
      news.category IN (".$categories.")

      Таким образом, будут выбраны все категории.

      Удалить
    3. Ну и в нагрузку)))
      Если все таки надо впихивать в value id всех категорий, то делаем value равным 1, 2, 3, 5 и т.д. (через запятую). А в js превращаем строку в массив идентификаторов, например так:
      categories=$('input[name="all_cat"]').value.split(',');

      Ну и дальше передавать массив так же в файл newsfilter.php

      Удалить
  3. Ответы
    1. Этот комментарий был удален автором.

      Удалить