Skip to content
7 changes: 7 additions & 0 deletions demos/form-control/tree-item-selector.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@
$control = $form->addControl('tree1', [Form\Control\TreeItemSelector::class, 'treeItems' => $items, 'allowMultiple' => false, 'caption' => 'Single selection:']);
$control->set(502);

$model = new File($app->db);
$control = $form->addControl('tree2', [Form\Control\TreeItemSelector::class, 'allowMultiple' => false, 'caption' => 'Selection from tree in Atk4/Model:',
'parentIdField' => $model->fieldName()->parent_folder_id]);

$control->setModel($model);

// $control->onItem(function (int $value) {
// return new JsToast('Received ' . $value);
// });
Expand All @@ -58,6 +64,7 @@
$response = [
'multiple' => $form->model->get('tree'),
'single' => $form->model->get('tree1'),
'model' => $form->model->get('tree2'),
];

$view = new Message('Items: ');
Expand Down
48 changes: 48 additions & 0 deletions src/Form/Control/TreeItemSelector.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Atk4\Ui\Form\Control;

use Atk4\Data\Model;
use Atk4\Ui\Form;
use Atk4\Ui\HtmlTemplate;
use Atk4\Ui\Js\Jquery;
Expand Down Expand Up @@ -39,6 +40,13 @@ class TreeItemSelector extends Form\Control
*/
public $loaderCssName = 'atk-tree-loader';

/**
* The field name which includes the parent node's id.
*
* @var string
*/
public $parentIdField = 'parent_id';

/** @var bool Allow multiple selection or just one. */
public $allowMultiple = true;

Expand Down Expand Up @@ -112,6 +120,46 @@ public function setTreeItems(array $treeItems)
return $this;
}

/**
* Recursive function to return sub-node for a given parent.
*
* @param $model : Model
* @param $nodes: array
* @param $parentId : int|string|null
*
* @return array|null
*/
protected function addNodes(Model $model, array $nodes, $parentId = null)
{
// return an array of items with parent = $parentId
$result = [];
foreach ($nodes as $node) {
if ($node[$this->parentIdField] === $parentId) {
$newNode = [];
$newNode['name'] = $node[$model->titleField];
$newNode['id'] = $node[$model->idField];
$newNode['parent_id'] = $node[$this->parentIdField];
$newNode['nodes'] = $this->addNodes($model, $nodes, $newNode['id']);
$result[] = $newNode;
}
}

if (count($result) > 0) {
return $result;
}

return null;
}

public function setModel(Model $model): void
{
parent::setModel($model);

$nodes_array = (clone $this->model)->export();
Copy link
Member

@mvorisek mvorisek Mar 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why clone? Why to materialize/export here?

Copy link
Contributor Author

@mkrecek234 mkrecek234 Mar 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Materialize is faster, as it does not involved a new DB query for every node. So up to you what is better - fix to use model only below.

$this->treeItems = $this->addNodes($model, $nodes_array);
unset($nodes_array);
}

/**
* Returns <input ...> tag.
*
Expand Down