DbHelp.ru
Маленький Yii блог
Комментарии
Гость: Намереваетесь оттрахать три киски сразу, обратите взо...
Гость: «Халва» - Карта Рассрочки взять кредит частный займ ...
Гость: Регистрируешься - огромный бонусы. Играешь - огромный ...
Гость: Быстро и качественно придам вашему фото идеальный вид....
Гость: Информативно,продолжай в том же духе [url=http://forum.oncolo...



Сервер Ultima Online - Forest Wars (от создателя данного блога)

Открытие узлов дерева через AJAX

Рубрика: Перевод Cookbook

Оцените эту статью:

Рейтинг: 0.00 (0)
11 мая 2010
Опубликовать в Twitter Написать в Facebook Опубликовать в своем блоге livejournal.com

Сегодня разговор снова пойдет про деревья :) Наткнулась мне заметка  «Display an AJAX tree from your DB using CtreeView» которую я решил рассказать у себя на DbHelp...

---

В этой статье мы научимся создавать дерево на yii (через CtreeView) заполняя его данными из базы. Но самое интересное во всем этом — мы будем использовать AJAX при открытии узлов, тем самым уменьшив нагрузку на базу.

ПОСМОТРЕТЬ DEMO

НАЧНЕМ

Для начала нам нужно создать таблицу в базе где и будут узлы дерева. Вариант дерева id-id_parent я очень часто использую в своих статьях, поэтому вы уже должны быть немного «в теме» :)

Заходим в базу и создаем новую таблицу:

CREATE TABLE `tree` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`name` VARCHAR( 50 ) NOT NULL ,
`parent_id` INT UNSIGNED NOT NULL
);

id – номер узла в дереве
name
– название узла
parent_id
– id узла родителя, которому подчиняется наш узел

 

КОНТРОЛЛЕР

В вашем контроллере должно быть два метода, первый (actionTree) — который будет рендерить виджет на экран и второй (actionAjaxFillTree) — который будет заниматся «открытием» дерева.

    public function actionTree()
    {
        // рендерим файлик отображения tree.php
        $this->render('tree');
    }

    public function actionAjaxFillTree()
    {
        // если пробуют получить прямой доступ к экшину (не через ajax)
        // тогда обрубаем "крылья")) т.е. возвращаем белую страницу
        if (!Yii::app()->request->isAjaxRequest) {
            exit();
        }
        // с какого узла начинаем вывод дерева? 0 - с первого
        $parentId = 0;
        if (isset($_GET['root'])) {
            // переменная $_GET['root'] говорит нам о том, по какому узлу в дереве
            // кликнули. Исходя из этого получаем данные детей (подкатегорий)
            $parentId = (int) $_GET['root'];
        }
        // сам запрос на получение данных детей (через обычный LEFT JOIN)
        $req = Yii::app()->db->createCommand(
            "SELECT m1.id, m1.name AS text, m2.id IS NOT NULL AS hasChildren "
            . "FROM tree AS m1 LEFT JOIN tree AS m2 ON m1.id=m2.parent_id "
            . "WHERE m1.parent_id <=> $parentId "
            . "GROUP BY m1.id ORDER BY m1.name ASC"
        );
        $children = $req->queryAll();
        // возвращаем данные
        echo str_replace(
            '"hasChildren":"0"',
            '"hasChildren":false',
            CTreeView::saveDataAsJson($children)
        );
        exit();
    }

Я написал комментарии к коду что б вам было легче понять к чему там дело. На самом деле все достаточно просто:

  • При первом входе на localhost/controller/tree/ происходит простой рендер дерева на экран и заполняется узлами первого уровня
  • При клике на узел дерева — происходит обращение к методу actionAjaxFillTree() для получения детей следующего узла

 

VIEW

В файле view/controller/tree.php просто инициализируем виджет:

<?php
$this->widget(
    'CTreeView',
    array('url' => array('ajaxFillTree'))
);>

И ЧТО ТЕПЕРЬ?

Добавтие в таблицу `tree` пару узлов с нулевым parent_id (т.е. первый уровень). Затем создайте несколько узлов со значениями parent_id = id узлов первого уровня. Например как у меня:

INSERT INTO `tree` (`id`, `name`, `parent_id`) VALUES
(10, 'молоко', 8),
(9, 'мед', 8),
(8, 'я НЕ люблю', 0),
(7, 'я люблю', 0),
(11, 'солнце', 8),
(12, 'море', 8),
(13, 'людей', 7),
(14, 'природу', 7),
(15, 'воздух', 7),
(16, 'спорт', 7),
(17, 'Футбол', 16),
(18, 'Биатлон', 16),
(19, 'Прыжки на лыжах с трамплина', 16),
(20, 'Сноубординг', 16);

После чего открывайте localhost/controller/tree и пробуйте как все красиво работает :)

 

Ссылки:



Если хотите опубликовать этот материал у себя - пожалуйста, разместите ссылку на страницу откуда вы его взяли.
Другие yii статьи:

  1. Хочу вас обрадовать выходном новой версии замечательного Yii фреймворка. Данный релиз был немного задержан посравнению с обычным графиком, но ... "Yii Framework 1.0.5"

  2. Долгожданный релиз 1.1.1 по праву можно назвать service pack к 1.1.0: исправлено более двадцати ошибок. Добавлено более тридцати улучшений и ... "Yii PHP framework 1.1.1 и 1.0.12"

  3. В процессе разработки приложения, очень часто требуется следить за запросами которые формирует фреймворк.В этом нам поможет FireBug, незаменимый инструмент ... "Логирование запросов в FireBug"

[adm] zolter

Было сказано: Среда, 12 Май 2010

Добавил в статью текст в отображание (view)

[guest] Гость

Было сказано: Среда, 12 Май 2010

прикольно, демо бы для ленивых :)

[adm] zolter

Было сказано: Среда, 12 Май 2010

У мну блог просто на 1.0.х написан))
Постараюсь поддомен сделать для 1.1 и туда кидать примеры

[guest] Гость

Было сказано: Четверг, 13 Май 2010

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

[adm] zolter

Было сказано: Четверг, 13 Май 2010

Готово :) Пример SQL-а тоже кинул для быстрого старта

[guest] Roman

Было сказано: Пятница, 14 Май 2010

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


Вот видно что происходило до добавления индекса и после. http://pastebin.com/wRe40WWv

Все еще напрягает temporary (group? )filesort (order? )

Вот тут с подзапросам без временной таблицы http://pastebin.com/asLFJDQm , как вариант я сортировку бы вообще на javascript перенес :)

[guest] zolter

Было сказано: Пятница, 14 Май 2010

Согласен, индексы всегда намного ускоряют выборки и работу с данными.

Я думаю что если читатель будет создавать таблицу tree у себя - то через мой SQL пример, а там id у меня как PRIMARY KEY.

[guest] Гость

Было сказано: Пятница, 14 Май 2010

Но parent_id не индекс. А именно он сократит количство рассматриваемых строк при джойне.

[guest] zolter

Было сказано: Пятница, 14 Май 2010

Аа понял о чем вы :)

[guest] Гость

Было сказано: Понедельник, 24 Май 2010

Неплохая статья :)

[guest] Alex

Было сказано: Вторник, 25 Май 2010

Подскажите, как сделать так чтобы каждый элемент поддерева был ссылкой?

[guest] Maxx

Было сказано: Вторник, 25 Май 2010

Я бы попробовал вместо имени типа "Дерево" делать "<a href='...'>Дерево</a>". Хотя может Золт что лучше скажет

[guest] Alex

Было сказано: Среда, 26 Май 2010

Попробывал ни чего не получилось, дерево вообще перестало отображаться.

[guest] zolter

Было сказано: Среда, 26 Май 2010

Вот так заработает:

INSERT INTO `zolter_blog`.`tree` (`id`, `name`, `parent_id`) VALUES (NULL, '<a href=''http://www.dbhelp.ru''>DbHelp.ru</a>', '7');


т.е. кавычки одинарные нужны или экранирование.

[adm] zolter

Было сказано: Среда, 26 Май 2010

Там слилось. Короче вместо:

<a href="http://www.dbhelp.ru">DbHelp.ru</a>

делай:
<a href='http://www.dbhelp.ru'>DbHelp.ru</a>

и все будет ок!

[guest] Alex

Было сказано: Среда, 26 Май 2010

я пытаюсь сделать древовидный каталог, ссылка будет примерно такой localhost/books/list/theme_id=3, где themes_id - это id элемента дерева, взятого из базы.
Нужно чтобы ссылки формировались вместе с деревом.

[guest] Гость

Было сказано: Пятница, 28 Май 2010

Еще, как вариант, можно ссылку организовать через CHtml::link();

[guest] Alex

Было сказано: Воскресенье, 30 Май 2010

Как я понял будет, вот так:
$link = str_replace(
'"hasChildren":"0"',
'"hasChildren":false',
CTreeView::saveDataAsJson($children)
);
echo CHtml::link($link, array('books/view',
'themes_id'=>$children->id)
);

Поправьте, если не верно, а то страшно.

[guest] Sova

Было сказано: Воскресенье, 13 Июнь 2010

Здравствуйте, автор, сделал все как у вас, но дерево не отображается в чем может быть проблема?


class TreesController extends Controller
{
public $layout='column2';
public function actionIndex()
{
// рендерим файлик отображения tree.php
$this->render('tree');
}
public function actionAjaxFillTree()
{
//ваш текст действия
}
}

[guest] Maxx

Было сказано: Вторник, 15 Июнь 2010

А в базу данные добавили?

[guest] Sova

Было сказано: Вторник, 15 Июнь 2010

В базе все есть. А конфликта версий нет, делал на 1.1.2 ?

Виталий

Было сказано: Среда, 16 Июнь 2010

Смотрю исходный код демо страницы в файрфоксе


...
<body>

<div class="container">
<div id="content">
<ul id="yw0">
</ul> </div><!-- content -->
</div>
<script type="text/javascript">
/*<![CDATA[*/
jQuery("#yw0").treeview({'url':'/yii-1.1.1.r1907/demos/blog/index.php/post/ajaxFillTree'});
/*]]>*/
</script>

Правильно ли я понимаю, что с точки зрения СЕО такие деревья не есть хорошо?

[guest] zolter

Было сказано: Среда, 16 Июнь 2010

Да, как и все другие ajax данные на странице - они не индексируются поисковиками.

[guest] net

Было сказано: Среда, 23 Июнь 2010

а есть ли возможность к данному виджету прикрутить запоминание состояния дерева?

[guest] zolter

Было сказано: Среда, 23 Июнь 2010

Вот этого не знаю.. Прикрутить то можна, а есть ли что то для этого в штатных средствах - подсказать немогу

[guest] Гость

Было сказано: Суббота, 12 Март 2011

там кто-то сверху писал, что не работает, хотя было все сделано как здесь.
тоже не работало.
потом глянул в файрбаге.
оказалось что просто в accessRules забыл добавить разрешение для действия actionAjaxFillTree.
файрбаг решает, при работе со скриптами

[guest] sape

Было сказано: Вторник, 12 Апрель 2011

>>>Да, как и все другие ajax данные на странице - они не индексируются поисковиками.

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

[guest] Гость

Было сказано: Среда, 18 Апрель 2012

демо не работает

[guest] Гость

Было сказано: Суббота, 19 Май 2012

Выдаёт пустую страницу.

[guest] Гость

Было сказано: Воскресенье, 17 Июнь 2012

Там просто ошибка в sql запросе)

[guest] Алексей

Было сказано: Понедельник, 29 Октябрь 2012

огромное спасибо:) когда только разбирался с Yii, ваша статья очень помогла, а в закладки не добавил, и потерял ее, вот сейчас снова натолкнулся, и не мог не поблагодарить:)

[guest] MalenkyMuk

Было сказано: Суббота, 08 Июнь 2013

Здравствуйте. Почему-то не передает значение root при нажатии на полученные пункты.

[guest] Гость

Было сказано: Воскресенье, 19 Январь 2014

почему-то ссылка демо открывает пустую страницу

[guest] DeD

Было сказано: Четверг, 04 Сентябрь 2014

Запрацювало тільки після заміни
if (isset($_GET['root']))
на
if (isset($_GET['root']) and $_GET['root'] != 'source')

І не потрібно весь код в контролері ліпити. А то люди так і напишуть. А загалом - дякую.

Оставить комментарий


Код:
Имя: