О web-разработке
и даже немного больше...

Зависимые списки (JQuery/Ajax)

Довольно часто на сайтах встречаются данные, которые можно визуально представить в виде структуры дерева. Дерево по своей структуре предусматривает зависимость одних подчиненных элементов, от других, корневых. Иногда на формах требуется сделать зависимые списки, говоря простым языком, это когда значения одного списка зависят от выбранного значения другого. Для наглядности давайте рассмотрим пример, как можно сделать подобные списки выбора.
 
Задача такова, на форме должны присутствовать два выпадающих списка. Первый из них будет содержать марки автомобилей, второй будет меняться динамически посредством Ajax запросов, тем самым получая данные по конкретной модели.
 
Создадим три файла: cars.php, form.php, ajax.php.
В файле cars.php будут храниться данные в виде массива, этот файл нам пригодится для подключения к двум другим файлам. Файл form.php содержит форму со списками, a ajax.php будет обрабатывать Ajax-запросы отправляемые из формы.

Файл cars.php:

<?php
$arModels = array(
	'BMW' => array(
		0 => '1-series',
		1 => '2-series',
		2 => '3-series',
		// ...
	),
	'Mercedes-Benz' => array(
		0 => 'A-класс',
		1 => 'B-класс',
		2 => 'C-класс',
		// ...
	),
	// и т.д.
);
?>

Ключи массива – это модели автомобилей в нашем представлении, вложенные массивы – серии для конкретных моделей.

Файл form.php:

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script>
<select name="model" onchange="loadCar(this)">
    <option>Модель</option>
    <?php
	require_once('cars.php'); // подключаем файл с данными
    foreach ($arModels as $model => $series){
        echo '<option value="' . $model . '">' . $model . '</option>' . "\n";
    }
    ?>
</select>
 
<select name="series">
    <option>Выберите модель</option>
</select>

<script>
function loadCar(select){
    var carSelect = $('select[name="series"]');
	$.getJSON('ajax.php', {
		action:'getModels',
		model:select.value
	}, function(seriesList){
        carSelect.html('');
        $.each(seriesList, function(i){
            carSelect.append('<option value="' + i + '">' + this + '</option>');
        });
    });
}
</script>

Для работы с формой мы будем использовать JQuery фреймворк, который следует подключать перед самой формой. Первый список содержит обработчик события OnChange, он инициализирует код для запроса данных для второго списка.

Файл ajax.php:

<?php
require_once('cars.php'); // подключаем файл с данными

if (isset($_GET['action']) && $_GET['action'] == 'getModels'){ // проверка параметров
    if (isset($arModels[$_GET['model']])) // если ключ найден
        echo json_encode($arModels[$_GET['model']]); // возвращаем массив с данными
    else // иначе
        echo json_encode(array('Выберите марку'));
    die;
}
?>

Файл, как ранее уже говорилось, будет отвечать на Ajax-запросы, и возвращать результат в формате Json.
Пример и исходники

UPD: В продолжение темы: как реализовать 3 зависимых списка?

Опубликован: 10.10.2014 г.

См. также:

Загрузка файлов на сервер посредством Ajax
Отложенная загрузка изображений Lazy Load
Анимация набора текста на Typed.js
Анимация отсчёта на jquery-spincrement
Mega Dropdown — Меню для мобильной версии
Отслеживаем клик вне элемента на JQuery
Ajax-загрузка записей при скроллинге и нажатии кнопки
Stimed – задаем CSS-стили по времени

Комментарии

  1. Валентин пишет:

    Добрый день! Подскажите, как реализовать 3 зависимых списка. Третий от второго, второй от первого: 1.Марка 2.Модель 3.Модификация модели.

    Спасибо!

    1. htmaker пишет:

      Добрый день. Добавил ссылку на второй пост в конце статьи.

  2. юрий пишет:

    Для файла form.php я приделал форму, метод post. Для приема создал файл b.php. Вместо моделей я сделал области и связал их с городами. В результате файл b.php получает область и номер города, а не сам город. Я не знаю яваскрипт, поэтому подскажите как получать город, а не его номер.

    1. htmaker пишет:

      к примеру у нас переменные:
      $_POST['model'] в ней значение 'BMW';
      $_POST['series'] в ней значение 2;

      // подключаем файл с данными
      require_once('cars.php');

      // а значение элемента массива получаем так
      echo $arModels[$_POST['model']][$_POST['series']]; // результат '3-series'

  3. Nts пишет:

    Здравствуйте. Тоже интересует вопрос который выше.. Никак не могу делать так, чтобы вместо вместо номера получить название серии в option value=" ". Код взял у Вас, подскажите пожалуйста где дописать ту строчку которая поможет?

    1. htmaker пишет:

      Здравствуйте, для этого в js функции loadCar() нужно подправить
      carSelect.append('<option value="' + this + '">' + this + '</option>');

  4. Ольга пишет:

    Добрый день!
    Спасибо за статью, очень помогло реализовать.
    Все работает, все классно, кроме одного маленького нюанса.
    Списки темизированы с помощью плагина core-ui-select
    Плагин загружается с загрузкой страницы, списки красивые. Но после выбора в первом списке, второй перегружается по аяксу, и красивый дизайн сбрасывается, а поскольку страница не перегружается, то плагин и не подключается снова, и список получается уродливым.
    Подскажите, что и где нужно прописать, чтобы плагин снова подгружался после аякс-перезагрузки?
    Пример здесь: zaphub.ru (фильтр по моделям авто).

    1. htmaker пишет:

      Добрый день. Можно попробовать вызвать

      $('select').coreUISelect();

      после того как список создан посредством Ajax.

  5. Александр пишет:

    Добрый день. Подскажите как сделать, чтобы эти данные извлекались из бд. В моем случае есть 2 таблицы с товаром (одежда) и размеры_цвета. Необходимо, чтобы при выборе цвета, также извлекались размеры (от выбора цвета). Спасибо!

    1. htmaker пишет:

      Добрый день. Не могли бы вы описать структуру таблиц в базе

      1. Александр пишет:

        таблица tovar:
        id
        title
        price
        brand
        datetime
        type_tovara //здесь записывается, например футболка из type (category)

        таблица category:
        cat_id
        type
        brand

        таблица colosize:
        cs_id
        cs_product_id //здесь записывается id тавара
        cs_size
        cs_color

        пример заполнения для последней таблицы 3 последних столбцов
        3
        M
        Красный

        3
        S
        Зеленый

        3
        S
        Синий

        4
        1
        S
        Оранжевый

        1
        S
        Коричневый

        1
        M
        Коричневый

        1
        xxl
        Коричневый

        1
        l
        Желтый

        А добавляются размеры и цвета - через товар (выбираем товар, id передается методом get, через 2 inputa пишем вручную размер и цвет)

        1. htmaker пишет:

          Итак, полагаю нужна таблица colosize, а конкретнее следующие поля:
          cs_product_id // id товара
          cs_size // размер
          cs_color // цвет

          Для товара нам предстоит первично узнать список доступных цветов.
          1. Выбор списка доступных цветов товара. В качестве переменной изначально у нас есть ID_товара. Делаем выборку цветов из таблицы:
          SELECT DISTINCT cs_color FROM colosize WHERE cs_product_id = 'ID_товара'
          Команда DISTINCT - фильтрует повторяющиеся в выборке записи, таким образом, список записей будет уникальным.

          2. Второй запрос подразумевает что у нас есть уже 2 переменные это: 'ID_товара' и 'значение_цвета', которые передаются посредством ajax-запроса. Выбираем доступные размеры товара согласно выбранному цвету:
          SELECT cs_size FROM colosize WHERE cs_product_id = 'ID_товара' AND cs_color = 'значение_цвета'

          Как в первом так и во втором случае результат передаете в json формате.

  6. Александр пишет:

    Меня также интересует как извлечь эти данные и записать их в массив?

    1. htmaker пишет:

      Как вы работаете с базой данных в своем проекте? Опишите ваши методы работы с базой.

      1. Александр пишет:


        $result1 = mysql_query("SELECT * FROM tovar WHERE id='$id' ", $link);
        if (mysql_num_rows($result1) > 0)
        {
        $row1 = mysql_fetch_array($result1);

        do
        {
        // выводится вся информация о товаре c картинками
        echo "Выберите цвет и размер";
        echo "";
        $result7 = mysql_query("SELECT * FROM colosize WHERE cs_product_id='$id' ORDER BY cs_color", $link);

        if (mysql_num_rows($result7) > 0)
        {
        $row = mysql_fetch_array($result7);
        do
        {
        echo '

        '.$row["cs_color"].' - '.$row["cs_size"].'

        ';
        }
        while ($row = mysql_fetch_array($result7));
        }
        echo "";
        }
        }
        while ($row1 = mysql_fetch_array($result1));

        1. htmaker пишет:
          $arResult = array();
          if (isset($_GET['id']) && isset($_GET['color'])){
          	
          	// приводим переданный id к типу int
          	$id = (int)$_GET['id'];
          	
          	// переводим все лишние символы в html сущности
          	$color = htmlspecialchars($_GET['color'],ENT_QUOTES);
          	
          	// выполняем запрос
          	$res = mysql_query("SELECT cs_size
          				FROM colosize
          				WHERE cs_product_id = '$id'
          				AND cs_color = '".mysql_escape_string($color)."'", $link);
          	if ($res){
          		if (mysql_num_rows($res) > 0){
          			while($arr = mysql_fetch_assoc($res)){
          				$arResult[] = $arr;
          			}
          		}
          	}
          }
          
          // отдаем результат
          echo json_encode($arResult);
          
          1. Александр пишет:

            Все понял. И такой еще вопрос (немного не по теме): У меня после выбора товара передаются данные (а именно только один id корзину, которая также добавляется в бд: ее структура - cart_id, cart_id_product,cart_price,cart_count,cart_datetime,cart_ip ). Обращение идет через ссылку с классом add-cart и дополнительным аттрибутом - tid="'.$row1["product_id"].' Никаких форм нет, потом появится select для цвета/размера. Необходимо, чтобы в эту таблицу добавлялся cs_id через ссылку. Два javascripta :

            $('.add-cart').click(function(){
            alert('Товар добавлен в корзину.');

            var tid = $(this).attr("tid");

            $.ajax({
            type: "POST",
            url: "include/addtocart.php",
            data: "id="+tid,
            dataType: "html",
            cache: false,
            success: function(data) {
            loadcart();
            }
            });

            });

            function loadcart(){
            $.ajax({
            type: "POST",
            url: "include/loadcart.php",
            dataType: "html",
            cache: false,
            success: function(data) {

            if (data == "0")
            {
            $("#block-basket > a").html("Корзина пуста");
            }
            else
            {
            $("#block-basket > a").html(data);
            }
            }
            });
            }

            addtocart:
            $id = $_POST["id"];

            $result = mysql_query("SELECT * FROM cart WHERE cart_ip = '{$_SERVER['REMOTE_ADDR']}' AND cart_id_product = '$id'", $link);
            if (mysql_num_rows($result) > 0)
            {
            $row = mysql_fetch_array($result);
            $new_count = $row["cart_count"] + 1;
            $update = mysql_query ("UPDATE cart SET cart_count='$new_count' WHERE cart_ip = '{$_SERVER['REMOTE_ADDR']}' AND cart_id_products ='$id'", $link);
            }
            else
            {
            $result = mysql_query("SELECT * FROM tovarWHERE product_id = '$id'", $link);
            $row = mysql_fetch_array($result);

            mysql_query("INSERT INTO cart(cart_id_products,cart_price,cart_datetime,cart_ip)
            VALUES(
            '".$row['product_id']."',
            '".$row['price']."',
            NOW(),
            '".$_SERVER['REMOTE_ADDR']."'
            )", $link);
            }
            }

            Необходимо, чтобы передалось cs_id в корзину

          2. Александр пишет:

            а в этой строке (data: "id="+tid,) что пишется?

        2. htmaker пишет:

          Добавьте при выборке размеров из таблицы colosize, ещё одно поле cs_id.
          Т.е. вы выбрали цвет, по ajax к вам будет возвращаться массив с cs_id и cs_size.

          Формируете из этих данных такой список:

          <select id="size">
          <option value="cs_id">cs_size</option>
          ...
          </size>

          При добавлении в корзину так же как и параметр tid, отправляете cs_id
          var cs_id = $("#size").val();

        3. htmaker пишет:

          Вместо

          data: "id="+tid,

          Следует указать

          data: {
          	id: tid,
          	csid: cs_id
          },
          
  7. Александр пишет:

    Я, конечно Вас замучал), но немного не получается(. Посмотрите если я загружу листинги? Можно через обратную связь?

  8. Игорь пишет:

    Ребята подскажите пожалуйста как эти файлы добавить в обычный html ничего не получается...

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Комментарии
  • Загрузка...
Друзья сайта