I'm using wbraganca dynamic forms. I have these codes in my controller :
public function actionView($id)
{
$rackObjects = RackObjects::find()->where(['rackID' => $id])->one();
if (!$rackObjects) {
throw new NotFoundHttpException('Empty rack');
}
return $this->render('view', [
'model' => $this->findModel($id),
'rackObjects' => $rackObjects,
]);
}
my view file :
<div class="col-lg-6">
<?= DetailView::widget([
'model' => $model,
'attributes' => [
'rackID',
'height',
'width',
],
]) ?>
</div>
<div class="col-lg-6">
<h3>Objects in <?= $this->title ?></h3>
<?= DetailView::widget([
'model' => $rackObjects,
'attributes' => [
'ObjectTitle',
'objectID',
'rack_unit',
'Attached'
],
]) ?>
</div>
I want to have all my rackObjects in multiple detailview not only one detailview like this example : http://wbraganca.com/yii2extensions/dynamicform-demo1/view?id=721
how should I write the codes like example? There is no codes in demos!
$rackObjects = RackObjects::find()->where(['rackID' => $id])->all();
probably as u have already tried all(),
i'd suggest a try in your view file along with querying all()
foreach ($rackObjects as $rackObject) {
<?= DetailView::widget([
'model' => $rackObject,
'attributes' => [
'ObjectTitle',
'objectID',
'rack_unit',
'Attached'
],
]) ?>
}
what it does is, when you have queried all, you get an array of objects and you might want to loop your widget over each of the objects. and gives you multiple detailViews as you desire.
hope this helps.
You are returnig only one row, as you specify
$rackObjects = RackObjects::find()->where(['rackID' => $id])->one();
Replace that with ->all();
Modify value of columns in you detail view if you want everything in one grid.
Amir zaghari.
I'm newbie in YII2 and I use wbraganca\dynamicform\DynamicFormWidget;
I try to follow your step to show data in Detailview but I got an error.
Undefined variable: id
maybe I made something wrong. so can you explain how to coding in
public function actionView($id)
in controller.php
and
DetailView::widget
to display data in _view.php
thank you, sir
Related
I'm trying to add multiple Select2 widgets dynamically in the TabularForm using Pjax (build-in Ajax component in Yii2). For some reason the Select2 input is rendering on the wrong place at the top of the view (see gif1 below). As I understood, this issue is related specifically to the Select2 widget as everthing is working fine if I use some default component e.g. Html::a (see gif2 below).
gif1: https://i.imgur.com/YMh5dNb.gif
gif2: https://i.imgur.com/sJkTDkO.gif
How I can get rid of that strange behaviour with the Select2 widget? Thanks is advance!
Controller:
class ProfileController extends Controller
{
// ...
public function actionCreate()
{
if (Yii::$app->request->isAjax) {
// some logic here ...
return $this->renderAjax('object/create', [
// ...
]);
}
}
// ...
}
View:
// ...
use kartik\select2\Select2;
use kartik\select2\Select2Asset;
Select2Asset::register($this);
// a bunch of html code
<?php Pjax::begin(['id' => 'product-add']); ?>
$form1 = ActiveForm::begin();
$attribs = [
'name' => [
'type' => TabularForm::INPUT_RAW,
'value' => function($productModel) {
return Select2::widget([
'name' => 'state_10',
'data' => ['1' => '1', '2' => '2'],
'pjaxContainerId' => 'product-add',
'options' => [
'placeholder' => $productModel->tmpId,
'multiple' => true
],
]);
//return Html::a('product ' . $productModel->tmpId); <- works fine if I use this piece of code
},
],
// ...
Html::a("Add", ['profile/create'], ['class' => 'btn btn-primary'])
// ...
<?php ActiveForm::end(); ?>
<?php Pjax::end(); ?>
// ...
After some closer examination I found the solution. For those who will also face the same issue, you need to initialize your widget (Select2 in my case) before the pjax response, e.g. in your Controller:
class ProfileController extends Controller
{
// ...
public function actionCreate()
{
if (Yii::$app->request->isAjax) {
// some logic here ...
// initialize the widget with an appropriate id
$this->view->registerJs("$({$product->tmpId}).select2();");
return $this->renderAjax('object/create', [
// ...
]);
}
}
// ...
}
And somewhere in your View:
Select2::widget([
'id' => $productModel->tmpId, // set your unique id here
'name' => $productModel->tmpId,
'data' => ['1' => '1', '2' => '2'],
// ...
]);
I have problems with loading data from database.
My goal is to implement a MVC which dynamically shows in the view the values stored in the db table. So, in the Project model I have this code:
public function search($params)
{
$query = project::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$this->load($params);
if (!$this->validate()) {
return $dataProvider;
}
// grid filtering conditions
$query->andFilterWhere([
'id' => $this->id,
'position' => $this->position,
'created_at' => $this->created_at,
'is_deleted' => $this->is_deleted,
]);
$query->andFilterWhere(['ilike', 'title', $this->title])
->andFilterWhere(['ilike', 'description', $this->description])
->andFilterWhere(['ilike', 'link', $this->link])
->andFilterWhere(['ilike', 'image', $this->image]);
return $dataProvider;
}
In the Controller:
public function actionIndex()
{
$searchModel = new SeachProject();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
And in the view (index.php):
<?= GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
'title',
'description',
'image',
],
]); ?>
Well, it works but I need to print the values into Uikit cards and not through Gridview limitations (which is actually the only way I know). I should have one card for each record in the table with an image (the url in the image field of the table) and a link (the url in the link field of the table).
Any words of advise would be good, thanks in advance!
You can use ListView and create any kind of structure using UiKit cards or material design.
The ListView widget is used to display data from a data provider. Each
data model is rendered using the specified view file. Since it
provides features such as pagination, sorting and filtering out of the
box, it is handy both to display information to end user and to create
data managing UI.
A typical usage is as follows:
use yii\widgets\ListView;
use yii\data\ActiveDataProvider;
echo ListView::widget([
'dataProvider' => $dataProvider,
'itemView' => '_ui-card',
'viewParams' => [
'fullView' => true,
'context' => 'main-page',
],
]);
The _ui-card view file could contain the following basic card html :
<?php
use yii\helpers\Html;
use yii\helpers\HtmlPurifier;
?>
<div class="uk-card">
<div class="uk-card-header">
<h3 class="uk-card-title"><?= Html::encode ( $model->title ) ?></h3>
</div>
<div class="uk-card-body"><img src="<?= Html::encode ( $model->image ) ?>"><?= Html::encode ( $model->link ) ?></div>
<div class="uk-card-footer"></div>
</div>
This way you can show every project as a separate card using the view file.
Hope this helps
I would like to combine 2 functions together, to consolidate code, and to be dynamic depending on how it is used. I do not know if this is possible.
First, lets lay out the basic use. In my example, I have Post and PostCategory models (and CRUD built). You create a category, then create a new post and assign it to the category. A post has the ability to be enabled or disabled. Essentially, you can create some new posts and have them not be viewable to the end users until your ready. One use-case would be a drip feed system, where you could add 100 posts and have one switch to enabled every x days. That is beyond the scope of this.
views\post\_form.php
<div class="post-form">
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($model, 'category_id')->dropDownList(
$model->getPostCategoryConst(),
['prompt'=> '- Category -']
)->label('Category')
?>
<?= $form->field($model, 'name')->textInput(['maxlength' => true]) ?>
<?= $form->field($model, 'text')->textarea(['rows' => 6]) ?>
<?= $form->field($model, 'status')->dropDownList(
$model->getPostStatusConst(),
['prompt'=> '- Status -']
) ?>
<div class="form-group">
<?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>
Notice the drop down lists for category_id and status and the functions they call
\common\models\Post.php
const STATUS_ENABLED = 1;
const STATUS_DISABLED = 0;
public function getCategory()
{
return $this->hasOne(PostCategory::className(), ['id' => 'category_id']);
}
/* -- Added -- */
public function getPostCategoryConst()
{
return ArrayHelper::map(PostCategory::find()->orderBy('name DESC')->all(), 'id', 'name');
}
public function getPostStatusConst()
{
return [
self::STATUS_DISABLED => 'Disabled',
self::STATUS_ENABLED => 'Enabled',
];
}
Now this works just fine :) However, I don't like using get as in getPostStatusConst() as it isn't accessed like $model->postStatusConst similar to how relations are with the "getter".
I would like to use these as "getters" as well though. In the index and view, it would be nice to also call the same functions. Instead of returning an array, to return a "nice name" such as "Enabled" or "Disabled"
For the sake of this, I won't rename the function, as I don't want to add any more confusion.
views\post\view.php
<?= DetailView::widget([
'model' => $model,
'attributes' => [
'id',
'category.name',
'name',
'text:ntext',
'postStatusConst', // <-- Calls getPostStatusConst()
'created_at:datetime',
'updated_at:datetime',
],
]) ?>
Notice postStatusConst is the same function as we used in _form for our create action. In the _form, it needed to return an array for the drop down list. In our view, it just needs to return a nice name such as Enabled or Disabled.
I Tried
I tried this function in the Post model:
public function getPostStatusConst()
{
if ( isset($this) ) {
return ($this->status === self::STATUS_ENABLED) ? 'Enabled' : 'Disabled';
}
return [
self::STATUS_DISABLED => 'Disabled',
self::STATUS_ENABLED => 'Enabled',
];
}
That obviously didn't work :) I didn't expect it to, because I know $this references itself in a class. It just shows what I am going for.
In relations, the hasOne() seems to know whether we are using it as a direct call (Post::getCategory) or inline ($model->category->name)..
Question
Is it possible to have getPostStatusConst() do the same? To use as $model->postStatusConst to display Enabled or Disabled nicely, or as Post::getPostStatusConst() to get the array for the drop down.
It is possible but really not worth all the changes in code. You would have to override magic __get() method and think about some way to store and access both returns in one structure.
I would leave getPostStatusConst() with current status name and add other method (even static) with the list of statuses for dropdown list.
I was pretty close. I wasn't thinking PHP OOP lines, but more Yii. A few Google searches and I slapped my forehead. When using frameworks, you forget your even writing in PHP sometimes ;)
public function getPostStatus()
{
if ( isset($this) && get_class($this) == __CLASS__) {
// not static
return ($this->status === self::STATUS_ENABLED) ? 'Enabled' : 'Disabled';
}
return [
self::STATUS_DISABLED => 'Disabled',
self::STATUS_ENABLED => 'Enabled',
];
}
I renamed the function so that it makes more sense.
It works everywhere. Lets see the index of my CRUD:
views\post\index.php
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'id',
'category.name',
'name',
//'text:ntext',
'postStatus',
// 'created_at',
// 'updated_at',
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
views\post\view.php
<?= DetailView::widget([
'model' => $model,
'attributes' => [
'id',
'category.name',
'name',
'text:ntext',
'postStatus',
'created_at:datetime',
'updated_at:datetime',
],
]) ?>
and views\post\_form.php
<?= $form->field($model, 'status')->dropDownList(
Post::getPostStatus(),
['prompt'=> '- Status -']
) ?>
All those cases seem to work fine. Anyone have any cases this would not work?
**i use model function in detail view how i use function in detail view **
<?= DetailView::widget([
'model' => $model,
'attributes' => [
'title',
'demand',
'sell_for',
'property_category',
'detail',
[
'attribute' => 'dealer_id',
'format'=>'raw',
'value'=> function ($model) {
return Dealer::getName($model->dealer_id);
}
],
],
]) ?>
**i use model function in detail view how i use function in detail view **
In DetailView value don't need anonymous function but only the assign ..
[
'attribute' => 'dealer_id',
'format'=>'raw',
'value'=> Dealer::getName($model->dealer_id);
],
see yii2 doc
return Dealer::getName($model->dealer_id)
Write out the code inside the getName function. If you want to get the name of the dealer using its id, then I think you should use the yii\db\ActiveQuery to sort that out. Lemme see your getName function
gii generated models successfully (with relations) :
/**
* #return \yii\db\ActiveQuery
*/
public function getClient()
{
return $this->hasOne(Client::className(), ['id' => 'client_id']);
}
but when i generated crud, in client filed just input text field.
Help me please, where is problem?
That's correct. In your _form.php file you have to define a dropdown box if the user should choose a client:
<?= $form->field($model, 'client')->dropDownList($clients) ?>
and in controller actions create/update you have to provide the $clients:
return $this->render('create', [ // or: return $this->render('update', [
'model' => $model,
'clients' => ArrayHelper::map(Client::find()->all(), 'id', 'name'),
]);
Don't forget to pass them in the view files for create.php and update.php to the _form.php file:
<?= $this->render('_form', [
'model' => $model,
'clients' => $clients, // <-- added
]) ?>
In other views where you just want to show client you may use this:
echo $model->client->name; //or something different