问题
I am working on Yii2
. I have created a tree using kartik tree manager. By default on each node click it shows me ID
, name
etc. But I want to show other data. Below is my code
<?=
TreeView::widget([
'query' => \common\models\MdcNode::find()->addOrderBy('root, lft'),
'headingOptions' => ['label' => 'Root'],
'rootOptions' => ['label'=>'<span class="text-primary">Root</span>'],
'topRootAsHeading' => true, // this will override the headingOptions
'fontAwesome' => true,
'isAdmin' => false,
//'nodeView' => '',
'toolbar' => [
TreeView::BTN_REFRESH => false,
TreeView::BTN_CREATE => false,
TreeView::BTN_CREATE_ROOT => false,
TreeView::BTN_REMOVE => false,
TreeView::BTN_SEPARATOR => false,
TreeView::BTN_MOVE_UP => false,
TreeView::BTN_MOVE_DOWN => false,
TreeView::BTN_MOVE_LEFT => false,
TreeView::BTN_MOVE_RIGHT => false,
],
'showIDAttribute' => false,
'showTooltips' => false,
'showNameAttribute' => false,
'softDelete' => false,
'cacheSettings' => ['enableCache' => true]
]);
?>
View
Update 1
After some RnD
I have found that the detail window is under <div id="w0-detail" class="kv-detail-container">
In my JS
I have tried to hide it $('#w0-detail').hide();
. Now I want to show the view on based on different nodes clicked.
Update 2
As per @Addi answer, I have updated my code
<?=
TreeView::widget([
'query' => \common\models\MdcNode::find()->addOrderBy('root, lft'),
'headingOptions' => ['label' => 'Root'],
'rootOptions' => ['label'=>'<span class="text-primary">Root</span>'],
'topRootAsHeading' => true, // this will override the headingOptions
//'displayValue' => 1, // initial display value
'isAdmin' => false,
'fontAwesome' => true,
//'nodeView' => '',
//show => none removes the iconType etc setting under details
'iconEditSettings'=>['show'=>'none'],
'toolbar' =>
[
TreeView::BTN_REFRESH => false,
TreeView::BTN_CREATE => false,
TreeView::BTN_CREATE_ROOT => false,
TreeView::BTN_REMOVE => false,
TreeView::BTN_SEPARATOR => false,
TreeView::BTN_MOVE_UP => false,
TreeView::BTN_MOVE_DOWN => false,
TreeView::BTN_MOVE_LEFT => false,
TreeView::BTN_MOVE_RIGHT => false,
],
'showIDAttribute' => false,
'showTooltips' => false,
'showNameAttribute' => false,
'softDelete' => false,
'cacheSettings' => ['enableCache' => true],
//removing the detail below removes the second column of view(s) 1 - 5. Section 5 is being used to render the extra data. See frontend\config\main.php later.
'mainTemplate'=>'<div class="row">
<div class="col-sm-3">
{wrapper}
</div>
<div class="col-sm-9">
{detail}
</div>
</div>',
'treeViewSettings'=> [
'nodeView' => '@kvtree/views/_form',
'nodeAddlViews' => [
1 => '',
2 => '',
3 => '',
4 => '',
5 => '',
]]
]);
?>
Now I am getting an error Setting unknown property: kartik\tree\TreeView::treeViewSettings
. I don't know why this error is showing. I must be missing something that I don't know and I am stuck to it
Any help would be highly appreciated.
回答1:
The following results were made without the need for js to hide the detail. By hiding the detail the nodeAddlViews will not be displayed. These nodes are contained in the {detail}. If you were to unhide the detail you would reveal the extra data in one of the 5 nodeAddlViews.
frontend\views\krajeeproducttree\index.php
<?php
use yii\helpers\Html;
use kartik\tree\TreeView;
use frontend\models\KrajeeProductTree;
$this->title = Yii::t('app','Houses');
$this->params['breadcrumbs'][] = $this->title;
$this->params['breadcrumbs'][] = ['label' => Yii::t('app','Index'), 'url' => ['krajeeproducttree/index']];
$this->params['breadcrumbs'][] = ['label' => Yii::t('app','Refresh Database with active houses'), 'url' => ['krajeeproducttree/populate']];
?>
<div class="krajeeproducttree-index">
<h1><?= Html::encode($this->title) ?></h1>
<?php
echo TreeView::widget([
// single query fetch to render the tree
'query' => KrajeeProductTree::find()->addOrderBy('root, lft'),
'headingOptions' => ['label' => 'Categories'],
'fontAwesome' => true, // optional
'isAdmin' => false, // optional (toggle to enable admin mode)
'displayValue' => 1, // initial display value
'softDelete' => true, // defaults to true
'cacheSettings' => [
'enableCache' => true // defaults to true
],
'hideTopRoot'=>true,
'treeOptions' => ['style' => 'height:1000px width:900px' ],
//more detail can be added to the node
'nodeLabel' => function($node) {
return $node->name;
},
//disable the toolbar completely
'toolbar' => [
TreeView::BTN_REFRESH => false,
TreeView::BTN_CREATE => false,
TreeView::BTN_CREATE_ROOT => false,
TreeView::BTN_REMOVE => false,
TreeView::BTN_SEPARATOR => false,
TreeView::BTN_MOVE_UP => false,
TreeView::BTN_MOVE_DOWN => false,
TreeView::BTN_MOVE_LEFT => false,
TreeView::BTN_MOVE_RIGHT => false,
],
'showIDAttribute' => false,
'showTooltips' => false,
'showNameAttribute' => false,
'softDelete' => false,
'cacheSettings' => ['enableCache' => true],
//show => none removes the iconType etc setting under details
'iconEditSettings'=>['show'=>'none'],
//remove the form buttons
'showFormButtons'=>false,
'breadcrumbs'=>[//'depth'=>null,
'glue'=>'»',
'activeCss'=>'kv-crumb-active',
'untitled'=>'Untitled'
],
//removing header below removes the search button and header
//'wrapperTemplate'=>'{header}{tree}{footer}',
'wrapperTemplate'=>'{tree}',
//removing the detail below removes the second column of view(s) 1 - 5. Section 5 is being used to render the extra data. See frontend\config\main.php later.
'mainTemplate'=>'<div class="row">
<div class="col-sm-3">
{wrapper}
</div>
<div class="col-sm-9">
{detail}
</div>
</div>'
]);
?>
</div>
I found the Treeview setup above, still left the breadcrumbs section of the {Detail} open with the save and reset buttons still enabled.
The isDisabled section in the model below is particularly important in not giving access to the save and reset button associated with the inbuilt breadcrumb section of vendor\kartik-v\yii2-tree-manager\src\views_form.php.(Line 184) as seen here:
if ($node->isDisabled()) {
$inputOpts['disabled'] = true;
}
frontend\models\krajeeproducttree.php
<?php
namespace frontend\models;
use Yii;
class KrajeeProductTree extends \kartik\tree\models\Tree
{
public static function getDb()
{
return \frontend\components\Utilities::userdb();
}
public static function tableName()
{
return 'works_krajee_product_tree';
}
public function isDisabled()
{
//so if the user is an admin he will be able to edit the tree otherwise the tree will be disabled
//but the nodes will be clickable and section 5 will be available.
if (Yii::$app->user->can('Manage Admin')) {
return false;
} else { return true; }
}
public function rules()
{
return [
[['product_id','productcategory_id','productsubcategory_id'],'integer'],
[['product_id','productcategory_id','productsubcategory_id'],'default','value'=>null],
[['product_id','productcategory_id','productsubcategory_id'],'safe']
];
}
}
The above model reflects the addition of 3 foreign keys each primary keys in their respective table that have been added to the Krajeeproducttree table.
The below controller builds a tree from these 3 tables. Everytime the user clicks on the refresh breadcrumb the tree is rebuilt.
frontend\controllers\KrajeeproducttreeController.php
<?php
namespace frontend\controllers;
use frontend\models\KrajeeProductTree;
use frontend\models\Productcategory;
use frontend\models\Productsubcategory;
use frontend\models\Product;
use kartik\tree\Controllers\NodeController;
use yii\filters\VerbFilter;
class KrajeeproducttreeController extends NodeController
{
public function behaviors()
{
return [
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
// 'delete' => ['POST'],
],
],
'access' =>
[
'class' => \yii\filters\AccessControl::className(),
'only' => ['index','populate'],
'rules' => [
[
'allow' => true,
'roles' => ['@'],
],
[
'allow' => false,
'roles' => ['?'],
],
[
'allow' => true,
'verbs' => ['POST']
],
],
],
];
}
public function actionIndex()
{
return $this->render('index');
}
public function actionPopulate()
{
//remove all data in the database
KrajeeProductTree::deleteAll();
//rebuild the database given data from productcategory ie. postcode, productsubcategory ie. street, product ie. house
//create the root and call it Run
$root = new KrajeeProductTree(['name'=>'Run']);
$root->makeRoot();
//create the postcode nodes
$allpostcodes =[];
$allpostcodes = Productcategory::find()->orderBy('id')->all();
foreach ($allpostcodes as $key => $value)
{
$newpostcodenode = new KrajeeProductTree(['name'=>$allpostcodes[$key]['name']]);
$newpostcodenode->productcategory_id = $allpostcodes[$key]['id'];
$newpostcodenode->prependTo($root);
$allstreets = [];
$allstreets = Productsubcategory::find()
->where(['productcategory_id'=>$allpostcodes[$key]['id']])
->all();
//create the street nodes associated with this new node
$allhouses = [];
foreach ($allstreets as $key => $value)
{
$newstreetnode = new KrajeeProductTree(['name'=>$allstreets[$key]['name']]);
$newstreetnode->productsubcategory_id = $allstreets[$key]['id'] ;
$newstreetnode->prependTo($newpostcodenode);
$allhouses = Product::find()
->where(['productsubcategory_id'=>$allstreets[$key]['id']])
->andWhere(['productcategory_id'=>$allstreets[$key]['productcategory_id']])
->andWhere(['isactive'=>1])
->all();
//create the house nodes associated with this new steet node
foreach ($allhouses as $key => $value)
{
$newhousenode = new KrajeeProductTree(['name'=>$allhouses[$key]['productnumber']]);
$newhousenode->product_id = $allhouses[$key]['id'];
$newhousenode->prependTo($newstreetnode);
}
}
}
return $this->render('index');
}
}
frontend\config\main.php under Modules section.
'treemanager' => [
'class' => 'kartik\tree\Module',
'treeViewSettings'=> [
'nodeView' => '@kvtree/views/_form',
'nodeAddlViews' => [
1 => '',
2 => '',
3 => '',
4 => '',
5 => '@app/views/krajeeproducttree/product',
]]
],
As has been mentioned by Kartik-v, the $node variable is inherited by the view if the view is listed under the treeViewSettings in the frontend\config\main.php.
frontend\views\krajeeproducttree\product.php
<?php
use Yii;
use yii\helpers\Url;
use yii\helpers\Html;
?>
<div class="krajeeproducttree-product">
<br>
<?php
if ($node->product_id > 0){
echo Html::a('<h4>View House Details: ' .$node->name. '</h4>',Url::toRoute(['/product/view','id'=>$node->product_id]));
}
if ($node->productsubcategory_id > 0){
echo Html::a('<h4>View Street Details: ' .$node->name. '</h4>',Url::toRoute(['/productsubcategory/view','id'=>$node->productsubcategory_id]));
}
if ($node->productcategory_id > 0){
echo Html::a('<h4>View Postcode Details: ' .$node->name. '</h4>',Url::toRoute(['/productcategory/view','id'=>$node->productcategory_id]));
}
?>
<br>
</div>
Hopefully this will be of assistance to you or perhaps someone in the future.
Response to Faisal: Confusing...Yes the product.php will only be useful if you have foreign id keys in your extended model pointing to their table so that you can link the node with a url to the controller/action/id associated with the table. I did this in order to avoid displaying a large amount of information if each node is clicked.
Here is the controller without the foreign keys:
public function actionPopulate()
{
//remove all data in the database
KrajeeProductTree::deleteAll();
//rebuild the database given data from productcategory ie. postcode, productsubcategory ie. street, product ie. house
//create the root and call it Run
$root = new KrajeeProductTree(['name'=>'Run']);
$root->makeRoot();
//create the postcode nodes
$allpostcodes =[];
$allpostcodes = Productcategory::find()->orderBy('id')->all();
foreach ($allpostcodes as $key => $value)
{
$newpostcodenode = new KrajeeProductTree(['name'=>$allpostcodes[$key]['name']]);
$newpostcodenode->prependTo($root);
$allstreets = [];
$allstreets = Productsubcategory::find()
->where(['productcategory_id'=>$allpostcodes[$key]['id']])
->all();
//create the street nodes associated with this new node
$allhouses = [];
foreach ($allstreets as $key => $value)
{
$newstreetnode = new KrajeeProductTree(['name'=>$allstreets[$key]['name']]);
$newstreetnode->prependTo($newpostcodenode);
$allhouses = Product::find()
->where(['productsubcategory_id'=>$allstreets[$key]['id']])
->andWhere(['productcategory_id'=>$allstreets[$key]['productcategory_id']])
->andWhere(['isactive'=>1])
->all();
//create the house nodes associated with this new steet node
foreach ($allhouses as $key => $value)
{
$newhousenode = new KrajeeProductTree(['name'=>$allhouses[$key]['productnumber']]);
$newhousenode->prependTo($newstreetnode);
}
}
}
return $this->render('index');
}
You will notice that children nodes are prepended to ie. prependTo the parent node. You can do this for all your models within your modules that you intend to create a tree for. You will also notice that the controller is extended from the NodeController.
Here is the format of the tables themselves.
Productcategory ie. Postcodes has an id autoincrement field. Productsubcategory ie. streets also has an id autoincrement field. In addition Productsubcategory has a foreign key productcategory_id that points to the Productcategory table.
The Product table ie. houses has its id autoincrement field. In addition it has two foreign keys ie. productsubcategory_id that points to the Productsubcategory table. It also has a foreign key productcategory_id that points to the Productcategory table.
This structure helps to link the three levels and also to use Yii2's relation modeling structure which is used in the above models in the above link.
Each street is linked to one postcode, ie. productcategory_id from table Productsubcategory (street) is the same as Productcategory table's id field, This structure also helps to retrieve data for each node. So the following code in the controller links the two levels:
$allstreets = Productsubcategory::find()
->where(['productcategory_id'=>$allpostcodes[$key]['id']])
->all();
Under the frontend\config\main.php you have added nodeView, is this necessary? also I can't find ...krajeeproducttree/product in your code.
nodeView is an alias concatenated with a path pointing to the view that renders the detail and is found on line 81 of vendor\kartik-v\yii2-tree-manager\src\Module. The default value is '@kvtree/views/_form' if not mentioned under the config\main.php. This _form is extended by the nodeAddlViews and has to exist if you want to show additional information. The _form can be modified and inserted under your model's views but will have to be correctly aliased eg @app \ views \krajeeproducttree \ _form.php.
Now I am getting an error Setting unknown property: kartik\tree\TreeView::treeViewSettings...
treeViewSettings is not a variable listed under \vendor\kartik-v\yii2-tree-manager\src\TreeView however on line 137, nodeView exists and on line 153 nodeAddlViews exists so you will be able to use these variables separately. ie. not within treeViewSettings for each separate Tree that you choose to build.
Also I can't find .....krajeeproducttree/product in your code...
Yes it would be expected that the controller KrajeeproductreeController would have an action called product to call up the product view product.php. This is normally expected but if you do a var_dump($node) in any of the views that you create for the nodeAddlViews you will get an array for $node. Normally you have to pass a parameter with the render in the controller eg.
return $this->render('index', [
'node' => $node
]);
but the fact that you are getting this automatically is mentioned here by Krajee.
Each of the views above will directly receive and can read the same parameters as mentioned in the nodeView section above (e.g. these will be available to the view as $node, $modelClass, $action etc.). In addition, the views will also receive the $form parameter, which is the ActiveForm instance (from kartik-v/yii2-widget-activeform).
So therefore there is no need for an action. The $node value is generated here:
Line 1211 in TreeView in the vendor folder
public function renderDetail()
{
/**
* @var Tree $modelClass
* @var Tree $node
*/
$modelClass = $this->query->modelClass;
$node = $this->displayValue ? $modelClass::findOne($this->displayValue) : null;
if (empty($node)) {
$node = new $modelClass;
}
The $node value is created when the detail is rendered.
来源:https://stackoverflow.com/questions/62386988/kartik-tree-view-show-different-views-on-each-node-click