Yii 1.1: simpletree

SimpleTree generates a drag'n'drop tree-view from ActiveRecords
41 followers

SimpleTree provides tree-view for ActiveRecords with drag'n'drop support for quick table manipulation. It uses the jsTree jQuery plugin from jstree.com.

Requirements

Yii 1.1 or above. Could possibly run on Yii 1.0 as well.

Usage

Unpack to your extension folder.

Make sure the Model you're using has properties/columns for the following: ID, parent ID, name and position. By default, these are respectively called id, id_parent, title and position.

/**
* Quick setup
**/
$this->widget('application.extensions.SimpleTreeWidget',array(
    'model'=>'MyModel',
));
/**
* Customized setup
**/
$this->widget('application.extensions.SimpleTreeWidget',array(
    'model'=>Folder::model()->findByPk(43),
    'modelPropertyParentId' => 'parent_id',
    'modelPropertyName' => 'name',
    'ajaxUrl' => '/ajax/simpletree',
    'onSelect'=>'
        var id = data.inst.get_selected().attr("id").replace("node_","");
        $("#contentBox").load("/ajax/getContent/id/"+id);
    '
));
 
//ajaxController
public function actionsimpletree()
{
    Yii::import('application.extensions.SimpleTreeWidget');    
    SimpleTreeWidget::performAjax();
}
/**
 * Parameters and defaults
 **/
 $ajaxUrl; //it is recommended that you use your own url
 $id = 'simpletree_widget';
 $model; //this can be the name of a model, an empty model or a loaded model
 $modelPropertyName = 'title'; //name of the name property in your model
 $modelPropertyId = 'id'; //name of the ID property in your model
 $modelPropertyParentId = 'id_parent'; //name of the parent ID property in your model
 $modelPropertyPosition = 'position'; //name of the position property in your model
 $theme = 'default'; //apple, classic, default
 $onSelect; //javascript
 $onCreate; //javascript
 $onMove; //javascript
 $onRemove; //javascript
 $onRename; //javascript

Changelog

January 27, 2011

  • Release 0.6

    • FEATURE: It is now possible to write protect a model with $Model->readonly = true;. Write protected models are not protected from indirect deletion in case one of its ancestors is deleted.
    • CHANGE: Models are now loaded via Ajax to accommodate large tables
    • FIX: It's no longer possible to drag folders outside the root folder(s)
    • FIX: Copied models now show correct IDs instead of "unidentified"
    • FIX: It's now possible to copy a copied model without the need to refresh first
  • Release 0.5b

    • CHANGE: onFocus has been renamed to onSelect and calls select_node() instead of on_focus()
    • FIX: calling data.inst._get_node() from onSelect (formerly onFocus) now returns the selected node rather than the previous selected node

January 26, 2011

  • Release 0.5
    • Initial release

Resources

jstree.com

jstree documentation

Total 20 comments

#17459 report it
Arslan Butt at 2014/06/17 01:45am
When Title is empty or with white space, the folder created we can resolve this issue
if (trim($params['title'])!='')
        {
//save function
}
 
else{
            echo json_encode(array('status'=>0));
        }
#17322 report it
heal at 2014/05/23 08:44am
root item

Hello, with this example

/**
* Customized setup
**/
$this->widget('application.extensions.SimpleTreeWidget',array(
    'model'=>Folder::model()->findByPk(43),
    'modelPropertyParentId' => 'parent_id',
    'modelPropertyName' => 'name',
    'ajaxUrl' => '/ajax/simpletree',
    'onSelect'=>'
        var id = data.inst.get_selected().attr("id").replace("node_","");
        $("#contentBox").load("/ajax/getContent/id/"+id);
    '
));

how can I make, that the root item have been rendered? I need this item (with primary key:43) beause without it I can't drag an element below the root.

#10807 report it
ApXaHgheJI at 2012/11/25 05:34pm
FIX THIS BUG

If you have any problems with sorting after refresh - find this line in method _get_children

foreach ($Model->findAllByAttributes(array($_REQUEST['modelPropertyParentId']=>$_REQUEST['id'])) AS $k => $Model)

and change it to

foreach ($Model->findAllByAttributes(array($_REQUEST['modelPropertyParentId']=>$_REQUEST['id']),array('order' => 'position')) AS $k => $Model)
#5885 report it
Agrippa at 2011/11/22 03:25pm
Got it

Finally I got it running.

Get rid of the "static"- Problem when I changed the "_get_Children"- function into "static function" (SimpleTreeWidget.php line 203).

I don't know if this results in some new problems, but so far everything seems to be smooth.

Thanks to the community and special thanks to doodle.

See u.

#5872 report it
Agrippa at 2011/11/21 03:58pm
Thanks doodle

Now I'm faced with this:

1>PHP Error [2048]</h1>
<p>Non-static method SimpleTreeWidget::_get_children() should not be called statically (C:\xampp\htdocs\yii\baum\protected\extensions\SimpleTreeWidget.php:245)</p>

Trying to get rind of it with no success:

ini_set('display_errors',1);
error_reporting(E_ALL|E_STRICT);

The lines in the Widged:

static function performAjax()
    {
        $Model = new $_REQUEST['model'];
        $method = '_'.$_REQUEST['operation'];
 
        header("HTTP/1.0 200 OK");
        header('Content-type: text/json; charset=utf-8');
        header("Cache-Control: no-cache, must-revalidate");
        header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
        header("Pragma: no-cache");
        self::$method($_POST);
 
    }

Strange anyway.

#5866 report it
got 2 doodle at 2011/11/21 09:10am
permissions problem

@ agrippa

I just realized that the accessRules need to be tweaked.

array('allow',
                'actions'=>array('index','simpletree','getContent'),
                'roles'=>array('member'),
      ),

doodle

#5863 report it
Agrippa at 2011/11/21 04:36am
Problem Rules

Hi, the problem was a rule. I've to login to solve the Login page thing.

But still not working because of a 403 error.

Damn, I will get this running by hook or by crook.

Regards

#5854 report it
Agrippa at 2011/11/20 07:11pm
further on

doodle

thanks again.

The Problem in my case seems to be the answer to the request. Firebug gives back the Login Page of the demo application. Therefor I Think there is something wrong with the Ajaxurl.

Could you please tell me where to point the ajaxurl?

Thanks for your endurance.

Of course the guide is my constant companion ;-). But its not easy cause I've got no programmers background.

Regards

#5850 report it
got 2 doodle at 2011/11/20 02:28pm
Explanation

@agrippa

$data = Categorydata::model()->pageID($page->id)->findAll(array('order'=>'position'));

The data table is simply that, in my case it is data associated with a web page. So the webpage has an id and the webpagedata has pageId field. In the above snippet pageID() is a method within the model, it helps build the mysql query, findAll() is a built in method and I pass an array that specifies what order to return the results in. Again it is just building a query.

public function pageID($id)
{
    $this->getDbCriteria()->mergeWith(array(
        'condition'=>'webpageid=:ID',
        'params'=>array(':ID'=>$id),
    ));
    return $this;
}

You should probably read the guide, if you have already read it, read it again. I read the guide a ton of times and I still refer to it all the time.

Regarding the simple tree widget, I suggest that you start with a very simple example but make sure that there are some values in the database or nothing will be displayed.

doodle

#5843 report it
Agrippa at 2011/11/19 06:08pm
Hi doodle

Thanks for the Re.

I don't figured out. Now I' am getting: <data.inst.get_selected().attr("id") is undefined>

What exactly does this Code do?:

$data = Categorydata::model()->pageID($page->id)->findAll(array('order'=>'position'));

Of course Categorydata is a Model, but what kind of values are in it? It seems this does a kind of relation between Category and Categorydata.

My Settings:

Controller:

/**
         * getContent
         * Ajax update
         * this updates the contents of #contentBox using _ajaxContent.php
         * gets the id of the page using $_GET['id]
         * if no id then id is set to zero and help page is displayed using _page_index.php
         * @name ajaxGetContent
         */
 
 public function actiongetContent()
  {
     if($_GET['id'] > 0)
      {
         $page = Category::model()->findByPk($_GET['id']);
         $data = Categorydata::model()->pageID($page->id)->findAll(array('order'=>'position'));
         $this->renderPartial('_ajaxContent',array('model'=>$page,'data'=>$data),false,true);
 
            }
         }
 
  public function actionsimpletree()
   {
    Yii::import('application.extensions.SimpleTreeWidget');
    SimpleTreeWidget::performAjax();
    }

Index:

$url = $this->createAbsoluteUrl('Category/getContent').'/&id=';
$this->widget('application.extensions.SimpleTreeWidget',array(
    'model'=>'Category',
    'modelPropertyParentId' => 'parent_id',
    'modelPropertyId'=>'id',
    'modelPropertyName' => 'name',
    'ajaxUrl' => $this->createAbsoluteUrl('Category/simpletree'),
    'onSelect'=>'
        var id = data.inst.get_selected().attr("id").replace("node_","");
        $("#contentBox").load("'.$url.'"+id);
    ',
 
 
));

And the _ajaxContent.php:

<?php echo $page ?>
<?php echo $data ?>

If I get it right, the function actiongetContent takes the ids(>0) out of Category Model and store it temporarily into the _ajaxContent.php. The Index file takes the ids out of the _ajaxContent.php, right?

Where can I go further?

Best Regards.

#5829 report it
got 2 doodle at 2011/11/17 07:28am
RE:No interactivity with the DB

@norbert 1: Definitely the table should have something in it if you want to see any nodes on the tree. If the table is empty there is nothing to display. 2: 'model'=>Category::model()->findByPk(43) this is requesting a single record so unless there is a record with id (43) you won't get anything, plus I doubt that this example would give any useful results unless it provide a collection of products for example and you are supplying the product category. I think it's kind of a half-baked example.

Here's an example of working code.

$url = $this->createAbsoluteUrl('SBPageadmin/getContent').'/&id=';
$this->widget('application.extensions.WebPageTreeWidget',array(
    'model'=>'Webpage',
    'modelPropertyParentId' => 'parent_id',
    'modelPropertyId'=>'id',
    'modelPropertyName' => 'name',
    'ajaxUrl' => $this->createAbsoluteUrl('SBPageadmin/simpletree'),
    'onSelect'=>'
        var id = data.inst.get_selected().attr("id").replace("node_","");
        $("#contentBox").load("'.$url.'"+id);
    ',
 
 
));

Notice that my example calls WebPageTreeWidget, that's because I copied the original file and tweaked it for my purposes.

In this example when you click on a node it calls this ajax routine.

/**
         * getContent
         * Ajax update
         * this updates the contents of #contentBox using _view_webpage.php
         * gets the id of the page using $_GET['id]
         * if no id then id is set to zero and help page is displayed using _page_index.php
         * @name ajaxGetContent
         */
 public function actiongetContent()
  {
     if($_GET['id'] > 0)
      {
$page = Webpage::model()->findByPk($_GET['id']);
$data = Webpagedata::model()->pageID($page->id)->findAll(array('order'=>'position'));
$this->renderPartial('_view_webpage',array('model'=>$page,'data'=>$data),false,true);
            } else {
               $this->renderPartial('help'.DIRECTORY_SEPARATOR.'_getting_started');
 
            }
         }

hope this helps to get you going.

doodle

#5826 report it
Agrippa at 2011/11/16 04:47pm
No interactivity with the DB

I try to run this extension unfortunately without success, just the same issue as in the comments: No interactivity with the DB. Could one please be so kind and give me a hint how to run this thing?

My settings so far:

in the Site Controller:

public function actionTree() { Yii::import('application.extensions.SimpleTreeWidget');
 SimpleTreeWidget::performAjax(); }

in the view/site/index:

$this->widget('appli

cation.extensions.SimpleTreeWidget',array(
 'model'=>Category::model()->findByPk(43),
 'modelPropertyParentId' => 'parent_id',
 'modelPropertyName' => 'name',
 'ajaxUrl' => '/ajax/simpletree', / also tried: 'ajaxUrl' => $this->createAbsoluteUrl('/site/simpletree'),
 'onSelect'=>'
 var id = data.inst.get_selected().attr("id").replace("node_","");
 $("#contentBox").load("/ajax/getContent/id/"+id);
 '
 )); ?>

The Table:

CREATE TABLE IF NOT EXISTS category ( id int(11) NOT NULL AUTO_INCREMENT, id_parent int(11) unsigned NOT NULL, position mediumint(5) unsigned NOT NULL, title varchar(255) NOT NULL, PRIMARY KEY (id) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=0 ;

Is it necessary to fill the table with values?

Best regards Norbert

#5740 report it
nlac at 2011/11/08 11:43am
way to improve

Hello,

maybe would be more elegant to extend the 'model' attribute with the possibility to give a db criteria in array format and introduce a new attribute 'theHasManyRelation'(string or array, the relation connecting the nodes) instead of 'modelPropertyId','modelPropertyPosition' and 'modelPropertyParentId'.

All of those could be easely posted in a serialized format on user events to the ajax controller.

#5537 report it
Kabinenkoffer at 2011/10/18 11:31am
Sorting Problem

Hi, first of all i realy like this extension. There is a little bug with the sorting of the tree. The tree is initialy not sorted by the position field. Here is a solution how to fix this. The Code in SimpleTreeWidget.php

public function _get_children()
    {
 
        $children = array();
        $Model = new $_REQUEST['model'];
        $criteria = new CDbCriteria();
        $criteria->order = $_REQUEST['modelPropertyPosition'];
        $criteria->condition =  $_REQUEST['modelPropertyParentId']."=:parent_id";
        $criteria->params = array(":parent_id"=>$_REQUEST['id']);
 
        foreach ($Model->findAll($criteria) AS $k => $Model)
....
....
#4591 report it
lees at 2011/07/22 10:40pm
Some change~~~~

you can add

if($params['id']=="")$params['id']=0;

in you _create_node like this !

if parent id is empty.were throw a error!

like this~~~

static function _create_node($params)
    {
        $Model = new $params['model'];
        if($params['id']=="")$params['id']=0;
#4584 report it
lees at 2011/07/22 04:50am
very good~

Thank you ~~~

#4233 report it
yiqing95 at 2011/06/17 01:02pm
it doesn't work when create two widgets in same page.

when i create two simpleTree in same page, only one display.

it seems that you haven't consider the id attribute ,or the htmlOptions:

/*  this id will be the tree container id , and the jstree will use it to initialize tree */
'htmlOptions'=>array('id'=>'simpleTree_'.mt_rand());

although there is a id attribute i can set ,but it seems to not work .

another thing: you should refer to jstree , even though it out of date, but the code technique is very good , or you may see this swfupload extension, these two js wrapper widgets only have little code , but it give the user more choices to config it. you can expose the under jstree config object to us like the swfupload extension do.

if people who didn't support the config ,then its your default setting config come out ,

at last , yours is a good extension , above words is only my advice , never mind if i say some thing wrong ! best regards :)

#4202 report it
yiqing95 at 2011/06/15 02:14pm
need i18n be supportted

the context menu should be i18n supportted , if can add or remove some menuitem will be better, what's this extension aim ,just for showing?

if in realistic project there should have more attributes to consider etc : mutli roots. ,there is a type field to differ from different categories . - can anyone give me some advice how to apply this extionsion in real project but a demo one. or does this extionsion can work togerther with the nestedSet and the EJNestedTreeActions ? any help will be appretiate

#3991 report it
got 2 doodle at 2011/05/25 08:20am
Security with cookies plugin

I just thought I would share a problem that I had when deploying this to my production server. The jquery.cookies.js file would not be served to the client because of security rules set in place by the hosting company.

This was their response when I asked for assistance. > The error you saw was being returned because access to the file was being blocked by a mod_security rule set in the server.

Before the change was made all that happened was an endless loading indicator and firebug reported that cookies.js could not be loaded.

doodle

#3795 report it
emc at 2011/05/08 01:14pm
just the one I need, but...

I am experiencing the same issue as justinas. It is not working with me as well :(

When I used the quick setup, only loading displays.

Then I used this as my customized setup:

//view
 
$this->widget('application.extensions.jsTree.SimpleTreeWidget',array(
    'model'=>'Menu',
    'ajaxUrl' => $this->createAbsoluteUrl('/site/simpletree'),
));
 
//controller
public function actionsimpletree()
{
    Yii::import('application.extensions.jsTree.SimpleTreeWidget');    
    SimpleTreeWidget::performAjax();
}

and what appeared is the folder "root". Yes I can create,move,edit,and delete a node, but what I am expecting to see is the tree derived from my table.

Leave a comment

Please to leave your comment.

Create extension