I've try to display my table columns data in listview but it's not working. In gridview it's allow to insert fields name. can't i do it in listview ?
I try this code.
$feedbackFound = new SqlDataProvider([
'sql'=> "SELECT * FROM feedback WHERE module_id='$tutorModule->id'",
]);
ListView::widget([
'dataProvider' => $feedbackFound,
//'filterModel' => $searchModel,
'itemView' => [
'PositiveComment',
'GoodAt',
'MakeMost',
//['class' => 'yii\grid\ActionColumn'],
],
]);
Unfortunately, sim`s answer doesn't work for me, that is why I have changed it a little:
$colsCount = 4;
echo ListView::widget([
'dataProvider' => $itemDataProvider,
'layout' => '{items}{pager}',
'options' => ['class' => 'TOP_CLASS_HERE'],
'itemOptions' => ['class' => "ITEM_CLASS_HERE"],
'beforeItem' => function ($model, $key, $index, $widget) use ($colsCount) {
if ($index % $colsCount === 0) {
return "<div class='row'>";
}
},
'itemView' => function ($model, $key, $index, $widget) {
return $this->render('#frontend/views/item/_card.php', ['item' => $model]);
},
'afterItem' => function ($model, $key, $index, $widget) use ($colsCount) {
$content = '';
if (($index > 0) && ($index % $colsCount === $colsCount - 1)) {
$content .= "</div>";
}
return $content;
},
]);
if ($itemDataProvider->count % $colsCount !== 0) {
echo "</div>";
}
I tested it on big amount of data and it works perfect. I like this solution, hope it helps somebody.
ListView doesn't have the fancy handling that gridview does - it takes data and passes it to a view, giving you some convenience items (pagination, sorting, filtering, etc).
The presentation and use of the convenience items is up to you. itemView is not analogous to the columns key for gridview. It's supposed to be a partial view (i.e. a php file you've created or a callback), so you need to define that partial view. That gives you a lot of flexibility in how each item from your data model is shown, but it requires some work.
Consider this code, it displays items from left to right, from top to bottom in a three columns. This code uses the following bootstrap css classes: col-sm-? and row to make a proper grid.
$columns = 3;
$cl = 12 / $columns;
echo ListView::widget([
'dataProvider' => $dataProvider,
'layout' => '{items}{pager}',
'itemOptions' => ['class' => "col-sm-$cl"],
'itemView' => '_view_list_item',
'options' => ['class' => 'grid-list-view' ],
'beforeItem' => function ($model, $key, $index, $widget) use ($columns) {
if ( $index % $columns == 0 ) {
return "<div class='row'>";
}
},
'afterItem' => function ($model, $key, $index, $widget) use ($columns) {
if ( $index != 0 && $index % ($columns - 1) == 0 ) {
return "</div>";
}
}
]);
if ( $dataProvider->totalCount % $columns != 0 ) {
echo "</div>";
}
This variant don't work with \yii\bootstrap\Tabs and pagination, because code always insert div:
//if ( $dataProvider->totalCount % $columns != 0 ) {
// echo "</div>";
//}
This variant work with \yii\bootstrap\Tabs and pagination:
if ( $dataProvider->totalCount % $columns != 0 ) {
if ($dataProvider->pagination->pageCount-1 == $dataProvider->pagination->page) {
echo "</div>";
}
}
Related
I am using wbraganca dynamic form widget. It works fine for the Create action.
Let me thanks for those guys making great tutorial video on youtube!!!
I am working on the Update action now. I work it on a purchase order function.
the controller of update action :
public function actionUpdate($id)
{
$model = $this->findModel($id);
$modelsItem = $model->purchaseitems;
if ($model->load(Yii::$app->request->post()) ) {
$oldIDs = ArrayHelper::map($modelsItem, 'purchaseitem_id', 'purchaseitem_id');
$modelsItem = Model::createMultiple(Purchaseitem::classname(), $modelsItem);
Model::loadMultiple($modelsItem, Yii::$app->request->post());
$deletedIDs = array_diff($oldIDs, array_filter(ArrayHelper::map($modelsItem, 'purchaseitem_id', 'purchaseitem_id')));
$valid = $model->validate();
$valid = Model::validateMultiple($modelsItem) && $valid;
if ($valid) {
$transaction = \Yii::$app->db->beginTransaction();
try {
if ($flag = $model->save(false)) {
if (! empty($deletedIDs)) {
Purchaseitem::deleteAll(['purchaseitem_id' => $deletedIDs]);
}
foreach ($modelsItem as $modelItem) {
$modelItem->purchaseitem_purchaseorder_id = $model->purchaseorder_id;
$modelItem->purchaseitem_description = Inventory::findOne($modelItem->purchaseitem_inventory_id)->inventory_partno;
if (! ($flag = $modelItem->save(false))) {
$transaction->rollBack();
break;
}
}
}
if ($flag) {
$transaction->commit();
return $this->redirect(['view', 'id' => $model->purchaseorder_id]);
}
} catch (Exception $e) {
$transaction->rollBack();
}
}
//return $this->redirect(['view', 'id' => $model->purchaseorder_id]);
} else {
return $this->render('update', [
'model' => $model,
'modelsItem' => (empty($modelsItem)) ? [new Purchaseitem] : $modelsItem
]);
}
}
But I think the problem may happen on the view file, as the Select2 field can show the value, which is the 'id' of the product rather than the product code.
view:
<div class="panel panel-default">
<div class="panel-body">
<?php DynamicFormWidget::begin([
'widgetContainer' => 'dynamicform_wrapper',
'widgetBody' => '.container-items',
'widgetItem' => '.item',
'limit' => 50,
'min' => 1,
'insertButton' => '.add-item',
'deleteButton' => '.remove-item',
'model' => $modelsItem[0],
'formId' => 'dynamic-form',
'formFields' => [
'purchaseitem_inventory_id',
'purchaseitem_qty',
'purchaseitem_cost_usd',
'purchaseitem_deliverydate',
],
]); ?>
<?php foreach ($modelsItem as $i => $modelItem): ?>
<div class="item">
<?php
// necessary for update action.
if (! $modelItem->isNewRecord) {
echo Html::activeHiddenInput($modelItem, "[{$i}]purchaseitem_id");
}
?>
<div class="row">
<?= $form->field($modelItem, "[{$i}]purchaseitem_inventory_id")->widget(
Select2::classname(), [
'pluginOptions' => [
'allowClear' => true,
'minimumInputLength' => 2,
'language' => [
'errorLoading' => new JsExpression("function () { return 'Error on finding results...'; }"),
],
'ajax' => [
'url' => Url::toRoute('inventory/inventorylist'),
'dataType' => 'json',
'data' => new JsExpression('function(params) { return {q:params.term}; }')
],
'escapeMarkup' => new JsExpression('function (markup) { return markup; }'),
'templateResult' => new JsExpression('function(purchaseitem_inventory_id) { return purchaseitem_inventory_id.text; }'),
'templateSelection' => new JsExpression('function (purchaseitem_inventory_id) { return purchaseitem_inventory_id.text; }'),
],
])->label(false) ?>
<?= $form->field($modelItem, "[{$i}]purchaseitem_qty")->textInput(['maxlength' => true])->label(false) ?>
<?= $form->field($modelItem, "[{$i}]purchaseitem_cost_usd")->textInput(['maxlength' => true])->label(false) ?>
<?= $form->field($modelItem, "[{$i}]purchaseitem_deliverydate")->widget(
DatePicker::className(), [
'options' => [
['placeholder' => 'Please enter delivery date'],
],
'removeButton' => false,
'pluginOptions' => [
'autoclose'=>true,
'format' => 'yyyy-mm-dd',
'todayHighlight' => true,
]
]
)->label(false) ?>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
I have a thought that the problem maybe related to that few lines of JsExpression function.
'escapeMarkup' => new JsExpression('function (markup) { return markup; }'),
'templateResult' => new JsExpression('function(purchaseitem_inventory_id) { return purchaseitem_inventory_id.text; }'),
'templateSelection' => new JsExpression('function (purchaseitem_inventory_id) { return purchaseitem_inventory_id.text; }'),
For the Select2 query URL method is here:
public function actionInventorylist($q = null, $id = null) {
Yii::$app->response->format = yii\web\Response::FORMAT_JSON;
$out = ['results' => ['id' => '', 'text' => '']];
if (!is_null($q)) {
$query = new Query;
$query->select('inventory_id AS id, inventory_partno AS text')
->from('inventory')
->where(['like', 'inventory_partno', $q])
->limit(10);
$command = $query->createCommand();
$data = $command->queryAll();
$out['results'] = array_values($data);
}
elseif ($id > 0) {
$out['results'] = ['id' => $id, 'text' => Inventory::find($id)->inventory_partno];
}
return $out;
}
I can load the record, when I click in the update view. Most of the data are feed in right place of the form, except the 'partno' field. I use Select2 to let user select partno by text and store the 'id' in table. It works on the Create view.
but in the update view, it only show the 'id' instead of the 'partno'.
if I make input to the field, I can select 'other' partno only, let me explain here:
if there are 2 code, "ABC" with 'id' is 1, "XYZ" with 'id' 2.
the record original is "ABC", the field show "1".
If I input "XYZ", it will show "XYZ" as normal effect of widget. But, if I change back to "ABC", it will show "1" instead of "ABC".
And the form also cannot submit for update. the button click with no effect.
I am new to Yii2 framework, and quite stuck on this issue, does anyone knows how can I solve this?
THANKS!!!!
I just solve the problem, a few issue happened actually.
To solve the Select2 widget cannot display the partno instead of the ID, I find the partno by the ID and feed it with initValueText in Select2. For my case:
$partno = empty($modelItem->purchaseitem_inventory_id) ? '':Inventory::findOne($modelItem->purchaseitem_inventory_id)->inventory_partno;
$form->field($modelItem, "[{$i}]purchaseitem_inventory_id")->widget(Select2::classname(), ['initValueText' => $partno, ...
About the update POST fail issue, I got error of Getting unknown property: backend\models\Purchaseitem::id, and I found it happened on the Dynamic-form widgets Model.php line 25. That lines is $keys = array_keys(ArrayHelper::map($multipleModels, 'id', 'id'));
If I change the 'id' to my ID field name, i.e 'purchaseitem_id', it will work, but this model will only work for this Id field name afterward. So I get the model's primaryKey and make it work for my other model.
add this line $primaryKey = $model->tableSchema->primaryKey; and modify above line $keys = array_keys(ArrayHelper::map($multipleModels, $primaryKey, $primaryKey));
How to change color of cell like this
if($data['type'] == 'London' or $data['type'] == 'Manchester' and $data['from_sale']){
return ['style' => 'background-color:#BCC6F0;'];
}
If in row 'type' value is London or Manchester then change color of cell in row 'from_sell'. Color must changed only in two cells in row 'from_sell'
Use contentOptions:
[
'attribute' => 'attribute_name',
'contentOptions' => function ($model, $key, $index, $column) {
return ['style' => 'background-color:'
. ($model->type == 'London' ? 'red' : 'blue')];
},
],
Since Yii uses Bootstrap you are better of using a Bootstrap class rather than style as below:
'contentOptions' => function($model) {
if ($model->taskduedt < date("Y-m-d")) {
return ['class' => 'table-danger',];
} elseif ($model->taskduedt == date("Y-m-d")) {
return ['class' => 'table-warning',];
}
else return ['class' => '',];
},
I have got this error while using the code below in DetailView of Yii 2.
Object of class Closure could not be converted to string
The code is:
[
'format' => 'raw',
'attribute' => 'title',
'value' => function($model1, $key) {
if ($model1->book->language == 1) {
$m = "<p class='n'>" . $model1->book->title . "</p>";
} else {
$m = $model1->book->title;
}
return $m;
},
'contentOptions' => ['class' => 'text-center'],
'headerOptions' => ['class' => 'text-center']
],
Can you guys help me?
DetailView does not take closure like GridView for value, just string. Change it to:
'value' => $model1->book->language == 1
? "<p class='n'>" . $model1->book->title . "</p>"
: $model1->book->title,
I need pjax to work on change status click and it's working fine but don't want it to change the URL as well. Below is the code:
<?php Pjax::begin(['id'=>'pjax-container-agency-index', 'timeout' => 10000, 'enablePushState' => true]); ?>
<?= GridView::widget([...,
[
'label' => 'Status',
'format' => 'raw',
'value' => function ($data) {
if ($data->deactive == 0) {
return Html::a(FA::i('circle'), ['agency/change-status', 'id' => $data->member_id, 'set' => 1], ['onclick' => "return confirm('Deactive this state/site?');", 'class' => 'status-inactive']);
} else {
return Html::a(FA::i('circle'), ['agency/change-status', 'id' => $data->member_id, 'set' => 0], ['onclick' => "return confirm('Active this state/site?');", 'class' => 'status-active']);
}
},
],
]);
<?php Pjax::end(); ?>
actionChangeStatus() is as below:
public function actionChangeStatus($id, $set) {
if (!empty($id) && isset($set)) {
$localGovt = $this->findModel($id);
$localGovt->deactive = $set;
if ($localGovt->save()) {
Yii::$app->getSession()->setFlash('success-status', 'State Status Changed');
} else {
Yii::$app->getSession()->setFlash('error-status', 'There is some error. Please consult with Admin.');
}
$searchModel = new AgencySearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider
]);
}
}
Note: I need 'enablePushState' => true for other events, so I can't change it to false inside Pjax::begin
I believe it's
'enableReplaceState' => true
Pass this attribute to Pjax:
Pjax::begin(['enablePushState' => false]);
This worked for me.
I have used use kartik\file\FileInput; (extension) for saving multiple images from single form submit.
The images are save locally but are not saving in the database.
Here is my Model Code media.php
namespace app\models;
use yii\web\UploadedFile;
class Media extends \yii\db\ActiveRecord
{
public function rules(){
return [
[['title'], 'file', 'skipOnEmpty' => false, 'extensions' => ['gif', 'jpg', 'png', 'jpeg', 'JPG', 'JPEG', 'PNG', 'GIF'], 'checkExtensionByMimeType' => false ,'maxFiles' => 4, 'maxSize' => 1024 * 1024 * 1024],
[['extension'], 'string', 'max' => 6],
];
}
Controller code:
if ($mediamodel->load ( Yii::$app->request->post () )) {
$title = UploadedFile::getInstances ( $mediamodel, 'title' );
foreach ($title as $key => $file) {
$file->saveAs(Yii::$app->basePath . '/web/images/hotel/'. $file->baseName . '.' . $file->extension);}
foreach ($title as $key => $file){
echo $mediamodel->title."*********";
$mediamodel->title = $file->baseName . '.' . $file->extension;
echo " \Title: ".$mediamodel->title;
$mediamodel->save ();
}
}
My view code:
use kartik\file\FileInput;
$form = ActiveForm::begin([ 'layout' => 'horizontal', {label}\n{beginWrapper}\n{input}\n{hint}\n{error}\n{endWrapper}",
'fieldConfig' => ['horizontalCssClasses' => ['label' => 'col-md-3','offset' => 'col-md-offset-2','wrapper' => 'col-md-4', 'error' => '','hint' => '',],],'
options' => [ 'class' => 'form-horizontal', 'enctype' => 'multipart/form-data', ], ]);?>
<?php echo $form->field($mediamodel, 'title[]')->widget(FileInput::classname(), ['options'=>['multiple' => true]]);
Html::submitButton($model->isNewRecord ? 'Add' : 'Update');
use
$mediamodel->save (false);
instead of
$mediamodel->save ();
// You should handle errors like this.
if(!$mediamodel->save()){
// handle the errors of model.
var_dump($mediamodel->getErrors());
}