I'm using Yii2 and i have a view which displays a table:
<div class="table-responsive">
<?php yii\widgets\Pjax::begin()?>
<?= GridView::widget([
'dataProvider' => $dataProvider,
'summary'=> "",
'tableOptions' => ['id'=>'smartTable',
'class' => 'display table-bordered-custom',
'cellspacing' => 0,
'width' => "100%"
],
'columns' => [
[
'class' => 'yii\grid\SerialColumn'],
'product_code',
'product_name',
'product_status',
[
'class' => 'yii\grid\ActionColumn',
'header' => 'Operation',
'template' => '{view}',
'headerOptions' => ['class' => 'no-sort'],
'buttons' => [
'view' => function ($url, $model) {
return Html::a(
'Edit<i class="material-icons">chevron_right</i>',
['update', 'id'=>$model->product_id],
[
'class' => 'btn',
'data-pjax' => '',
]
);
},
],
],
],
]);
?>
<?php Pjax::end(); ?>
</div>
My controller:
class ProductController extends Controller
{
/**
* #inheritdoc
*/
public function behaviors()
{
return [
'verbs' => [
'class' => VerbFilter::class,
'actions' => [
'delete' => ['POST'],
],
],
];
}
/**
* Lists all Product models.
* #return mixed
*/
public function actionIndex()
{
$dataProvider = new ActiveDataProvider([
'query' => Product::find(),
'sort' => false,
'pagination'=> [
'pageSize' => 4
]
]);
return $this->render('index', [
'dataProvider' => $dataProvider,
]);
}
}
Edit: My controller has a simple action called index.
My problem is that when i click on the page number and get new info, all the styles I've given to my table disappear.
If i remove Pjax everything is okay because the entire page reloads.
Why? please help me.
I finally managed to fix this! but i'm not sure it's the best.
With pjax events you can solve such problems:
$(document).on("pjax:success", function() {
$('#smartTable').DataTable({
"paging": false,
"responsive": true,
"dom": 'iftlp',
"bProcessing": true,
"aoColumnDefs": [ // EXCEPT SORTING
{'bSortable': false, 'aTargets': ['no-sort']}
],
});
$('#simpleTable').DataTable({
"responsive": true,
"dom": 't'
});
});
So every time our pjax is successfully executed, we will re-apply the style we need.
That's it, i hope to be useful to others.
Thanks to pjax that we can reload selective content easily.
Issue
In Yii2, pjax also do try to loads the anchors (links) etc present inside the pjax container within the same container. Which means it doesn't allow such links to load, full pages. This causes crippling of the other parts / tags in followed pages.
Solution
In order to avoid this, you need to figure out a way to load your links/pages outside the pjax container. One method that worked for my action links is as following:
Example
This is my custom actions column:
[
'label'=>'Options',
'format' => 'raw',
'value'=>function ($data) {
return Html::a('<i class="glyphicon glyphicon-eye-open"></i>', ['short-message/conversation', 'id'=> $data["id"]], ['onclick' =>'window.location.href=this.getAttribute("href")']);
},
],
Explanation
You can see that I have used onclick method to follow the link using JavaScript:
['onclick' =>'window.location.href=this.getAttribute("href")']
Related
I have install the miloschuman\highcharts\Highcharts, website : https://www.yiiframework.com/extension/yii2-highcharts-widget. I have a database with the table columns lme_price and lme_name which I want to display the price of the copper in the highcharts. I'm using PHP.
Below is my code which I have done. This is the code in my models. I create a static function with the query inside it to find the data that I want from the database.
public static function getCopperPrice()
{
$getCopperPrices = Lme::find()
->select('lme_price')
->where(['lme_name' => 'LME Copper'])
->all();
return $getCopperPrices;
}
Here is my code in the view. I have a table show in the view which show every data from the database.
<div class="lme_index">
<?= GridView::widget([
'dataProvider' => $dataProvider,
// 'searchModel'=> $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
[
'label'=> 'DATE',
'attribute' => 'lme_title',
],
[
'label'=> 'MATERIAL',
'attribute'=> 'lme_name',
],
[
'label'=> 'PRICE (US$)',
'attribute'=> 'lme_price',
],
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
Here is the code for the highcharts graph.
<div class = "graph">
<?= Highcharts::widget([
'options' => [
'title' => ['text' => 'Copper Price'],
'xAxis' => [
'categories' => []
],
'yAxis' => [
'title' => ['text' => 'Price $US']
],
'plotOption' => [
'series' => [
['name' => 'Copper',
'data' => [lme::getCopperPrices()]],
]
]
]
]);?>
I want to display only 1 material price in the highcharts. I call the function from the model inside the series but the graph shows nothing on it. The coding there didn't show any error to me.
Can someone help me or tell me how to solve this? Thanks.
Chart require integer values to display
public static function getCopperPrice()
{
$cooperPrices = [];
$copperPriceList = Lme::find()
->select('lme_price')
->where(['lme_name' => 'LME Copper'])
->column();
foreach($copperPriceList as $price) {
$cooperPrices[] = (int) price;
}
return $cooperPrices;
}
I want to set a default configuration for all my GridViews.
I did this as following:
app\config\web.php:
require __DIR__ . '/container.php';
app\config\container.php:
use yii\helpers\Html;
use yii\helpers\Url;
\Yii::$container->set('yii\grid\GridView', [
'layout' => "{items}\n{summary}\n{pager}",
'columns' => [
[
'class' => 'yii\grid\ActionColumn',
'template' => '{edit}{update}',
'buttons' => [
'edit' => function ($url, $model) {
return Html::a('<span class="glyphicon glyphicon-pencil"></span>', [Url::to(['edit', 'id' => $model->id])]);
},
],
],
],
]);
the part where I define the layout works fine.
But apparently the part with the ActionColumn doesn't work, because the whole array-index 'columns' gets overwritten by the column-names when I actually use the GridView in a list.
How can I set default settings for ActionColumn for all GridViews?
Try setting the default values for ActionColumn separately:
\Yii::$container->set('yii\grid\ActionColumn', [
'template' => '{edit}{update}',
'buttons' => [
'edit' => function ($url, $model) {
return Html::a('<span class="glyphicon glyphicon-pencil"></span>', [Url::to(['edit', 'id' => $model->id])]);
},
],
]);
I cannot seem to figure out why pjax reloads the page on the second form submission. It works exactly as intended on the first form submission pulling from this url /site/profile?UserSearch%5Bsearchstring%5D=mi&_pjax=%23form-pjax, however, after that first one it loses the ending of the url /site/profile?UserSearch%5Bsearchstring%5D=m. I checked the actual html code and the form is retaining the data-ajax attribute. I tried increasing the timeout as had been suggested when pjax is reloading the entire page, but that did not change anything.
Below is the code from my view
<?php Pjax::begin(['timeout' => 5000, 'id' => 'form-pjax']); ?>
<?php $form = ActiveForm::begin([
'method' => 'get',
'action' => Url::to(['site/profile']),
'options' => ['data-pjax' => true ],
]); ?>
<?= $form->field($searchModel, 'searchstring', [
'template' => '<div class="input-group">{input}<span class="input-group-btn">' .
Html::submitButton('Search', ['class' => 'btn btn-default']) .
'</span></div>',
])->textInput(['placeholder' => 'Find friends by username or email']);
?>
<?php ActiveForm::end(); ?>
<?= GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
'username',
[
'label' => 'View Profile',
'format' => 'raw',
'value'=>function ($data) {
return Html::a(Html::encode("View Profile"),'/site/redirectprofile/'.$data->id);
},
],
[
'label' => 'Follow',
'format' => 'raw',
'value'=>function ($data) {
return Html::a(Html::encode(Follow::find()->where(['user_id' => $data->id, 'follower_id' => Yii::$app->user->Id])->exists() ? 'Unfollow' : 'Follow'),'/site/follow/'.$data->id.'/'.$data->username);
},
],
],
'summary'=>'',
]); ?>
<?php Pjax::end(); ?>
You must call needed javascript triggers/functions after every pjax reload like:
$('#form-pjax').on('pjax:success', function() {
/*call Your functions here, or copy from your generated page js code,
that bind event to pjax form,
at end of generated html You should have something like: */
jQuery(document).on('submit', "#form-pjax form[data-pjax]", function (event) {
jQuery.pjax.submit(event, '#form-pjax', {"push":true,"replace":false,"timeout":000,"scrollTo":false});
});
});
This is not yii2 issue, it's how javascript works, when You add dynamically content it's needed to bind triggers/events for every added element.
I have a view that shows 2 gridviews of the same model class, however, they seem to use the same filter, sort and pagination, even though they use different search models and dataProviders like so:
In the controller:
public function actionIndex()
{
$searchModel = new CasoAccionSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
$dataProvider->pagination->pageParam = "tarea-propia-page";
$dataProvider->sort->sortParam = "tarea-propia-sort";
$searchModelTerceros = new CasoAccionSearch();
$dataProviderTerceros = $searchModelTerceros->search(Yii::$app->request->queryParams);
$dataProviderTerceros->pagination->pageParam = "tarea-3ros-page";
$dataProviderTerceros->sort->sortParam = "tarea-3ros-sort";
return $this->render('myIndex', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
'searchModelTerceros' => $searchModelTerceros,
'dataProviderTerceros' => $dataProviderTerceros,
]);
}
And in the view:
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
// ['class' => 'yii\grid\SerialColumn'],
'acc_referencia',
'acc_fecha_accion',
'fecha_creacion',
[
'label' => 'Creado Por',
'format' => 'raw',
'value' => function($data){
return $data->abCreador->nombreCompleto;
}
],
//'ab_creacion',
[
'label' => 'Caso',
'format' => 'raw',
'value' => function($data){
return Html::a($data->caso->caso_nombre,
Yii::$app->urlManager->createUrl(['caso/view','id'=>$data->caso_id]));
}
],
// 'caso.caso_nombre',
'acc_descripcion:ntext',
'caso.caso_referencia',
[
'label' => 'Cliente',
'format' => 'raw',
'value' => function($data){
return Html::a($data->caso->cliente->nombreCliente,
Yii::$app->urlManager->createUrl(['cliente/view','id'=>$data->caso->cl_id]));
}
],
// 'resp_id',
// 'acc_tipo',
// 'estado',
// 'acc_horas_estimadas',
// 'acc_horas_ejecutadas',
// 'acc_fecha_accion',
// 'acc_descripcion:ntext',
// 'fecha_creacion',
// 'ab_creacion',
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
<?= GridView::widget([
'dataProvider' => $dataProviderTerceros,
'filterModel' => $searchModelTerceros,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'acc_referencia',
'acc_fecha_accion',
'fecha_creacion',
'caso.caso_nombre',
[
'label' => 'Responsable',
'format' => 'raw',
'value' => function($data){
return $data->abResponsable->nombreCompleto;
}
],
//'abResponsable.ab_nombres',
'acc_descripcion:ntext',
'caso.caso_referencia',
[
'label' => 'Cliente',
'format' => 'raw',
'value' => function($data){
return Html::a($data->caso->cliente->nombreCliente,
Yii::$app->urlManager->createUrl(['cliente/view','id'=>$data->caso->cl_id]));
}
],
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
Any ideas about how to make them behave independently?
I see you have already configured different pagination and sorting parameters for both models. That is correct, so all you need to fix is filtering.
Your filtering applies to both grids, because your form element names are the same. Your search model has the formName() method, which returns a string. By default, it returns class name. So, when you try to filter on acc_referencia in any of the forms, the following parameter is added to your url: CasoAccionSearch[acc_referencia]. It is then picked up by both grids which is not your desired behavior. What you should make instead is grid1[acc_referencia] for first grid and grid2[acc_referencia] for second grid.
You have two choices here: either implement CasoAccionSearch::formName() in such a way that it returns two different form names for two different instances of CasoAccionSearch, or just use two different search models.
I suggest you do it this way:
class CasoAccionSearch
{
public $formNameParam = 'CasoAccionSearch';
// ...
// other attributes
public function formName()
{
return $this->formNameParam;
}
// ...
// other methods
}
And then in your view:
$searchModel = new CasoAccionSearch(['formNameParam' => 'grid1']);
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
For consistency, I would also make pageParam and sortParam attributes of CasoAccionSearch that get passed to the data provider in search().
They use the same class CasoAccionSearch() and then the same search function .. if you need two separated function you need a proper search function eg:
class CasoAccionSearch extends CasoAccion
{
.....
public function search($params)
{
.......
}
public function search2($params) // searc for second grid
{
.......
}
and the adapt you controller/action code for use the two different search function ..
How can I sort with a customized gridview header?
Please give the difference between label and header in the Yii2 gridview widget dataprovider.
Here is my code:
<?= GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
[
'class' => 'yii\grid\DataColumn',
'value' => function ($data) {
return $data->myTitle;
},
'headerOptions' => ['style'=>'text-align:center'],
'header' => 'Page Title',
'label' => 'Title'
],
]); ?>
Do header and label perform the same function?
How can I perform sorting in $data->myTitle?
Here my Output Screen:
I want Page Title, Status, Date Modified should be active.
Thanks in advance.
Found the answer.
Please add attributes to ActiveDataProvider in your Search Model.
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => [
'pageSize' => 5,
],
'sort' => ['attributes' => ['myTitle']],
]);
Add the attribute option in widget:
<?= GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
[
'class' => 'yii\grid\DataColumn',
'value' => function ($data) {
return $data->myTitle;
},
'headerOptions' => ['style'=>'text-align:center'],
'attribute' => 'myTitle',
'label' => 'Page Title'
],
]); ?>
Since myTitle is a field from the database and not a custom value, you can just use attribute. The rest may be unnecessary e.g the default class is DataColumn
'columns' => [
[
'attribute' => 'myTitle',
'label' => 'Label',
]
I am not very sure I understand your question, but sorting option can be included in your modelsearch.php. So in your case you have to do like this.
$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort'=> ['defaultOrder' => ['your_column'=>SORT_ASC]]
]);
if myTitle is a field in the database, why you are using such a long syntax. Just
'Columns'=>[
..
'myTitle',
..
],
should work fine and should be active for sorting as you want
if you want a different header/label for the column, use label instead of header as header is only a cell content and cannot be used for sorting, while label can. details
[
..
'attribute'=>'myTitle',
'label' => 'Page Title'
..
],