I create filter form for my data using data provider and search model and have a problem, when my filter parameters copy in url when I click submit button more than one time.
Model's ApartmentsSearch search method:
public function search($params)
{
$query = Apartments::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
$query->andFilterWhere([
'rooms' => $this->rooms,
]);
return $dataProvider;
}
Controller actionIndex method:
public function actionIndex()
{
$searchModel = new ApartmentsSearch();
$dataProvider = $searchModel->search(Yii::$app->request->get());
return $this->render('index', [
'dataProvider' => $dataProvider,
'searchModel' => $searchModel,
]);
}
View with ListView widget:
<?= $this->render('_filter', ['searchModel' => $searchModel]); ?>
<?= ListView::widget([
'dataProvider' => $dataProvider,
'itemView' => '_list',
'options' => [
'tag' => 'div',
'class' => 'apartments-list',
],
'layout' => '{summary}{items}{pager}',
'summary' => 'Показано квартири: <b>{begin}-{end}</b> з <b>{totalCount}</b>.',
'summaryOptions' => [
'tag' => 'div',
'class' => 'summary',
],
'itemOptions' => [
'tag' => 'div',
'class' => 'apartment-item',
],
]); ?>
And _filter.php view with form:
<?php $form = ActiveForm::begin([
'method' => 'get',
]); ?>
<?= $form->field($searchModel, 'rooms') ?>
<div class="form-group">
<?= Html::submitButton('Search', ['class' => 'btn btn-primary']) ?>
<?= Html::resetButton('Reset', ['class' => 'btn btn-default']) ?>
</div>
<?php ActiveForm::end(); ?>
So, when I input any number in field and click submit I see url like this:
http://localhost/?ApartmentsSearch[rooms]=2
When I click second time I see url with copied parameter:
http://localhost/?ApartmentsSearch[rooms]=2&ApartmentsSearch[rooms]=2
I don't want copy parameters in url, I need to change value of any parameter.
Can you help me?
Solved.
In active form I forgot add action property:
<?php $form = ActiveForm::begin([
'action' => ['index'],
'method' => 'get',
]); ?>
<?= $form->field($searchModel, 'rooms') ?>
<div class="form-group">
<?= Html::submitButton('Search', ['class' => 'btn btn-primary']) ?>
<?= Html::resetButton('Reset', ['class' => 'btn btn-default']) ?>
</div>
<?php ActiveForm::end(); ?>
Related
I am trying to use Yii2's conditional validator within DynamicModel clas, but the validator when is not working:
Controller
private function createFormModel(){
$model = new DynamicModel([
'indicador',
'departamento',
'mes'
]);
$model->addRule(['indicador'],'required',['message' => 'Este campo es obligatorio']);
$model->addRule(['departamento'], 'required', ['when' => function ($model) {
return $model->indicador == 'Semana';
}]);
return $model;
}
public function actionCuatrimestre()
{
$model = $this->createFormModel();
return $this->render('cuatrimestre',[
'model' => $model,
]);
}
Whether I select or not the "indicador" field which is a select field, the "departamento" field alwasys returns as required. I have algo try this way but with no results:
$model->addRule(['departamento'], 'required', ['when' => function ($model) {
return $model->indicador == 'Semana';
}], ['whenClient' => "function (attribute, value) {
return $('#indicador').val() == 'Semana';
}"]);
What I am missing here?
EDIT
My view code cuatrimestre.php
<?php $form = ActiveForm::begin(); ?>
<div class="form-group">
<?= $form->field($model, 'indicador')->widget(Select2::class, [
'options' => ['id'=>'indicador'],
'data' => ['Semana','Día','Resumen'],
]); ?>
</div>
<div class="form-group">
<?= $form->field($model, 'departamento')->widget(Select2::class, [
'options' => ['id'=>'departamento'],
'data' => Departamentos::getDepartamentosByUser(),
]); ?>
</div>
<div class="form-group">
<?= $form->field($model, 'curso')->widget(DepDrop::class, [
'type' => DepDrop::TYPE_SELECT2,
'options' => ['id' => 'curso-id'],
'select2Options' => ['pluginOptions' => ['allowClear' => true]],
'pluginOptions' => [
'depends' => ['departamento-id'],
'placeholder'=>'Seleccionar curso',
'url' => Url::to(['/campus-actividad/subcursos']),
'loadingText' => 'Cargando ...',
'initialize' => true,
]
]);?>
</div>
<div>
<?= Html::submitButton('Aplicar filtros', ['class' => 'btn btn-block btn-default']) ?>
<?php ActiveForm::end(); ?>
</div>
I had a problem with Pjax, actually on somepage I load a view in Modal, and in this modal I use GridView with filter option with selectbox. When user changes the filter, the content will not be updated, but the page will be redirected to the filtered URL (Gridview with data updated).
When the view is working outside the modal it works fine, and update its contents!
Here is my code:
index.php, here I load my modal:
<div>
<?php
Modal::begin([
'header' => '',
'id' => 'modal-window',
'class' => 'modal',
'footer' => 'Close',
'clientOptions' => ['backdrop' => false]
]);
Modal::end();
?>
And in view:
<?php Pjax::begin(['id' => 'pjax_translation','enablePushState' => false, 'timeout' => false,]); ?>
<div class="row">
<h1><?= Html::encode($this->title) ?></h1>
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'filterUrl' => Url::to(["translate/view" , "id" => $id ]),
'tableOptions' => ['class' => 'table table-striped table-bordered translate-list',"style"=> ""],
'options' => ['data-pjax' => true ],
'columns' => [
[
'attribute' => 'language',
'filter' => $arrLanguage,
'content'=> function($model) use ($arrLanguage){
return isset($arrLanguage[$model->language])? $arrLanguage[$model->language] : "" ;
},
'headerOptions' => ['width' => '150'],
],
[
'attribute' => 'translation',
],
],
]); ?>
</div>
<?php Pjax::end(); ?>
And in my controller the code is:
public function actionView($id)
{
$view = "view";
$searchModel = new TranslateMessageSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
$dataProvider->query->andFilterWhere([
'id' => $id,
]);
if (Yii::$app->request->isAjax) {
\Yii::$app->response->format = 'json';
$html = $this->renderAjax($view, [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
'id'=>$id,
]);
return ['success' => true, 'html' => $html] ;
} else {
return $this->render($view, [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
'id'=>$id,
]);
}
}
i found finally a solution after three days testing everything. I will post it here, maybe it could be usefull for someone who has the same problem.
I just put in my view.php the following js at the top:
$js = "$(document).on('submit', 'form[data-pjax]', function(event) {
$.pjax.submit(event, '#pjax_translation', {
'push': false,
'replace': false,
'timeout': 5000,
'scrollTo': false,
'maxCacheLength': 0
});
});";
$this->registerJs($js);
and everything is work fine now :)
this is working for me:
<?php Modal::begin([
'header' => '',
'id' => 'modal-window',
'class' => 'modal',
'toggleButton' => ['label' => 'click me'],
'footer' => 'Close',
'clientOptions' => ['backdrop' => false]
]); ?>
<?php Pjax::begin() ?>
<?php $form = ActiveForm::begin(['options' => ['data-pjax' => 1]]) ?>
<?= date('Y-m-d H:i:s', time()) ?> <button type="submit">click this</button>
<?php ActiveForm::end() ?>
<?php Pjax::end() ?>
<?php Modal::end(); ?>
PS: Maybe your page gets reloaded because you hit Pjax timeout
There are some questions here, but the problem is in the filters that are in the gridview.
My problem is that I can not integrate an external form with the gridview itself because I do not want to use the search form that is part of the gridview.
Controller
public function actionIndex()
{
$searchModel = new BlogSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
Views
index.php
<?= Html::button('Filter', ['data-toggle' => 'modal', 'data-target' => '#filter-modal', 'class' => 'btn btn-primary']) ?>
<?php
Modal::begin([
'header' => '<h3>Search Blog</h3>',
'id' => 'filter-modal'
]);
echo $this->render('_search', ['model' => $searchModel]);
Modal::end();
?>
<?php Pjax::begin(); ?>
<?= GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
'title',
'content'
]
]); ?>
<?php Pjax::end(); ?>
_search.php
<?php $form = ActiveForm::begin([
'action' => ['index'],
'method' => 'get',
]); ?>
<?= $form->field($model, 'title') ?>
<?= $form->field($model, 'content') ?>
<div class="form-group">
<?= Html::submitButton('Search', ['class' => 'btn btn-primary']) ?>
</div>
<?php ActiveForm::end(); ?>
In the "index.php" the gridview is inside the pjax, but the search form is outside, but even if the form was within "Pjax :: begin" it would not work, either.
That is, when I do the search the page is reloaded. I want only gridview updatated.
As far as I understood from the discussion you don't want to use the filter fields inside the GridView and want to use the search form instead to filter the GridView. if that is correct you need to do 2 things for that
1. Move your form inside the pjax block
index.php
<?= Html::button('Filter', ['data-toggle' => 'modal', 'data-target' => '#filter-modal', 'class' => 'btn btn-primary']) ?>
<?php Pjax::begin(['enablePushState'=>false]); ?>
<?php
Modal::begin([
'header' => '<h3>Search Blog</h3>',
'id' => 'filter-modal'
]);
echo $this->render('_search', ['model' => $searchModel]);
Modal::end();
?>
<?= GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
'title',
'content'
]
]); ?>
<?php Pjax::end(); ?>
2. And the second an most important thing is to include the option of data-pjax inside the form options.
_search.php
<?php $form = ActiveForm::begin([
'action' => ['index'],
'id'=>'my-form',
'method' => 'get',
'options' => [
'data-pjax' => 1
],
]); ?>
<?= $form->field($model, 'title') ?>
<?= $form->field($model, 'content') ?>
<div class="form-group">
<?= Html::submitButton('Search', ['class' => 'btn btn-primary']) ?>
</div>
<?php ActiveForm::end(); ?>
EDIT
You might find problem with the modal overlay staying there and the modal window itself hides, provide your form with an id like id=>"my-form" and add the following inside your _search.php file to bind the beforeSubmit event for ActiveFormJS
$this->registerJs('$("#my-form").on("beforeSubmit", function (e) {
$("#filter-modal").modal("hide");
});', \yii\web\View::POS_READY);
I have created a Global Search with grid view displaying, but this is the problem for the first time that the search page loads or when the search field is empty and you search, all the data in the db will be displayed.
and I have used the _search.php view inside another view.
_search view:
<?php $form = ActiveForm::begin([
'action' => ['index'],
'method' => 'get',
]); ?>
<?= $form->field($model, 'globalSearch') ?>
<div class="form-group">
<?= Html::submitButton('Search', ['class' => 'btn btn-primary']) ?>
<?= Html::resetButton('Reset', ['class' => 'btn btn-default']) ?>
</div>
<?php ActiveForm::end(); ?>
the main view:
<?php echo $this->render("../ads/_search", ['model' => $model]); ?>
<?php Pjax::begin(); ?>
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $model,
'showOnEmpty' => false,
'summary' => '',
'showFooter' => false,
'showHeader' => false,
'columns' => [
'name',
'type',
'explanation',
'address',
'province_name',
'cost',
],
]);?>
<?php Pjax::end(); ?>
Anything else is needed? Let me know.
If you want to display the grid, let the filter model return a data provider with no results when global search is empty
class FilterModel extends Model {
public $globalSearch;
::
::
public function search($params) {
$provider = new ActiveDataProvider(
$query = SomeModel::find();
);
if (!$this->globalSearch) {
$query->where('1=0'); // returns no results
return $provider;
}
// other code to return results with filter applied
::
::
return $provider;
}
}
I don't know how you applied this globalSearch filter, but this is default behavior of grid filters: when filters not defined - GridView will display matched data items (=== all items).
But if you want change this behavior you can simply not render GridView in the case of empty filter:
<?php echo $this->render("../ads/_search", ['model' => $model]); ?>
<?php
if(!empty($model->globalSearch)){
Pjax::begin();
echo GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $model,
'showOnEmpty'=>false,
'summary'=>'',
'showFooter'=>false,
'showHeader' => false,
'columns' => [
'name',
'type',
'explanation',
'address',
'province_name',
'cost',
],
]);
Pjax::end();
}
?>
I want to use pagination in my view, but I can't figure out how to do it in conjunction with the find() method.
Getting the numbers of pages works correctly, but it always displays all values from the database. I want to see 15 comments per page.
Here is my ViewAction controller:
public function actionView($id) {
$query = UrComment::find()->where(['IsDeleted' => 0]);
$pagination = new Pagination(['totalCount' => $query->count(), 'pageSize'=>12]);
return $this->render('view', [
'model' => $this->findOneModel($id),
'comment' => UrComment::findComment($id),
'pagination'=> $pagination
]);
}
And this is how I get the comments:
public static function findComment($id)
{
if (($model = UrUser::findOne($id)) !== null) {
$Id=$model->Id;
$comment = UrComment::find()->where(['Rel_User' => $Id])->all();
return $comment;
} else {
throw new NotFoundHttpException('The requested page does not exist.');
}
}
I tried to use this:
public function actionView($id) {
$query = UrComment::find()->where(['IsDeleted' => 0]);
$pagination = new Pagination(['totalCount' => $query->count(), 'pageSize'=>12]);
$comment= UrComment::findComment($id);
$comment->offset($pagination->offset)
->limit($pagination->limit)
->all();
return $this->render('view', [
'model' => $this->findOneModel($id),
'comment' =>$comment,
'pagination'=> $pagination
]);
}
But I get this error:
Call to a member function offset() on array
Then I display it in the view:
<?php
use yii\helpers\Html;
use yii\widgets\DetailView;
use yii\helpers\Url;
/* #var $this yii\web\View */
/* #var $model backend\modules\users\models\UrUser */
$this->title = $model->Name;
$this->params['breadcrumbs'][] = ['label' => Yii::t('app', 'Użytkownicy'), 'url' => ['index']];
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="ur-user-view">
<h1><?= Html::encode($this->title) ?></h1>
<p>
<?= Html::a(Yii::t('app', 'Aktualizuj'), ['update', 'id' => $model->Id], ['class' => 'btn btn-primary']) ?>
<?=
Html::a(Yii::t('app', 'Usuń'), ['delete', 'id' => $model->Id], [
'class' => 'btn btn-danger',
'data' => [
'confirm' => Yii::t('app', 'Jesteś pewien, że chesz usunąć tego użytkownika?'),
'method' => 'post',
],
])
?>
</p>
<?=
DetailView::widget([
'model' => $model,
'attributes' => [
'Id',
'Name',
'Surname',
'BirthDate',
'Login',
'Email:email',
['attribute' => 'Rel_Sex', 'value' => (isset($model->relSex->Name)? $model->relSex->Name : "Nie wybrano")],
['attribute' => 'Rel_Language', 'value' => (isset($model->relLanguage->Name)) ? $model->relLanguage->Name : "Nie wybrano"],
['attribute' => 'Rel_Country', 'value' => (isset($model->relCountry->Name)) ? $model->relCountry->Name : "Nie wybrano"],
['attribute' => 'Rel_Category', 'value' => (isset($model->relUserCategory->Name)) ? $model->relUserCategory->Name : "Nie wybrano"],
],
])
?>
Komentarze użytkownika: <?= $model->Name.' '.$model->Surname;?><br><br>
<?php foreach ($comment as $comm): ?>
<?= Html::a(Yii::t('app', 'Edytuj'), ['update-user-comment', 'id' => $comm->Id], ['class' => 'btn btn-primary']) ?>
<?=
Html::a(Yii::t('app', 'Usuń'), ['delete-comment', 'id' => $comm->Id], [
'class' => 'btn btn-danger',
'data' => [
'confirm' => Yii::t('app', 'Jesteś pewien, że chesz usunąć tego użytkownika?'),
'method' => 'post',
],
])
?>
<p><?= $comm->Text ?></p>
<hr>
<?php endforeach; ?>
<?php
echo \yii\widgets\LinkPager::widget([
'pagination' => $pagination,
]);
?>
</div>
</div>
</div>
How can I limit the UrComment::findComment($id) using the pagination?
EDIT:
I think I understand you, and I think I've done everything you told me in your answer, but now I have another problem. I need to display under view comments only that which is id view only this one person not all comments.
Here is what I have now:
ActionView:
public function actionView($id) {
$searchModel = new CommentSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
$dataProvider->query->andWhere(['IsDeleted' => 0]);
$dataProvider->pagination->pageSize=15;
return $this->render('view', [
'model' => $this->findOneModel($id),
'comment' => UrComment::findComment($id),
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
CommentSearch:
<?php
namespace backend\modules\users\models;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use common\models\UrComment;
class CommentSearch extends UrComment
{
public function rules() {
return [
[['Id'], 'integer'],
[['Text'], 'safe'],
];
}
public function scenarios() {
// bypass scenarios() implementation in the parent class
return Model::scenarios();
}
public function search($params) {
$query = UrComment::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$this->load($params);
if (!$this->validate()) {
// uncomment the following line if you do not want to return any records when validation fails
// $query->where('0=1');
return $dataProvider;
}
$query->andFilterWhere([
'Id' => $this->Id,
'Text' => $this->Text,
]);
$query->andFilterWhere(['like', 'Text', $this->Text]);
return $dataProvider;
}
}
View:
<?php
use yii\helpers\Html;
use yii\widgets\DetailView;
use yii\helpers\Url;
use yii\widgets\ListView;
/* #var $this yii\web\View */
/* #var $model backend\modules\users\models\UrUser */
$this->title = $model->Name;
$this->params['breadcrumbs'][] = ['label' => Yii::t('app', 'Użytkownicy'), 'url' => ['index']];
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="ur-user-view">
<h1><?= Html::encode($this->title) ?></h1>
<p>
<?= Html::a(Yii::t('app', 'Aktualizuj'), ['update', 'id' => $model->Id], ['class' => 'btn btn-primary']) ?>
<?=
Html::a(Yii::t('app', 'Usuń'), ['delete', 'id' => $model->Id], [
'class' => 'btn btn-danger',
'data' => [
'confirm' => Yii::t('app', 'Jesteś pewien, że chesz usunąć tego użytkownika?'),
'method' => 'post',
],
])
?>
</p>
<?=
DetailView::widget([
'model' => $model,
'attributes' => [
'Id',
'Name',
'Surname',
'BirthDate',
'Login',
'Email:email',
['attribute' => 'Rel_Sex', 'value' => (isset($model->relSex->Name)? $model->relSex->Name : "Nie wybrano")],
['attribute' => 'Rel_Language', 'value' => (isset($model->relLanguage->Name)) ? $model->relLanguage->Name : "Nie wybrano"],
['attribute' => 'Rel_Country', 'value' => (isset($model->relCountry->Name)) ? $model->relCountry->Name : "Nie wybrano"],
['attribute' => 'Rel_Category', 'value' => (isset($model->relUserCategory->Name)) ? $model->relUserCategory->Name : "Nie wybrano"],
],
])
?>
Komentarze użytkownika: <?= $model->Name.' '.$model->Surname;?><br><br>
<?php
echo ListView::widget([
'dataProvider' => $dataProvider,
'itemView' => 'comments',
'viewParams' => ['comment' => $comment, 'model'=>$model],
]);
?>
</div>
</div>
</div>
And my item comments:
<?php
use yii\helpers\Html;
use yii\widgets\DetailView;
use yii\helpers\Url;
/* #var $this yii\web\View */
/* #var $model backend\modules\users\models\UrUser */
?>
<?= Html::a(Yii::t('app', 'Edytuj'), ['update-user-comment', 'id' => $comment->Id], ['class' => 'btn btn-primary']) ?>
<?=
Html::a(Yii::t('app', 'Usuń'), ['delete-comment', 'id' => $comment->Id], [
'class' => 'btn btn-danger',
'data' => [
'confirm' => Yii::t('app', 'Jesteś pewien, że chesz usunąć tego użytkownika?'),
'method' => 'post',
],
])
?>
<p><?= $comment->Text ?></p>
<hr>
Using that code, now I have error that in this item in button edit:
$comment->Id], ['class' => 'btn btn-primary']) ?>
Trying to get property of non-object
And I can't use foreach there because I have duplicate comments. Should change something in comment Search or in my function findComment(id) inquiry?
There is my actual item 'comments' where I want to display text of comments and buttons to edit and delete comment. But this does not work for me. I have:
Use of undefined constant Id - assumed 'Id'
and
Use of undefined constant Text - assumed 'Text';
<?php
use yii\helpers\Html;
use yii\widgets\DetailView;
use yii\helpers\Url;
/* #var $this yii\web\View */
/* #var $model backend\modules\users\models\UrUser */
?>
<?= Html::a(Yii::t('app', 'Edytuj'), ['update-user-comment', 'id' => Id], ['class' => 'btn btn-primary']) ?>
<?=
Html::a(Yii::t('app', 'Usuń'), ['delete-comment', 'id' => Id], [
'class' => 'btn btn-danger',
'data' => [
'confirm' => Yii::t('app', 'Jesteś pewien, że chesz usunąć tego użytkownika?'),
'method' => 'post',
],
])
?>
<p><?= Text ?></p>
<hr>
If you use model and foreach in not easy, use pagination because pagination if base on dataProvider and not directly for model ..
Essentially finding the model like you did mean work direclty on the data while pagination don't work directly on the data but rather use the a sql query for retrive information from db a let these available to widgets .. this is what the dataProvider perform .. .. then I suggest you of use a widget like ListView and change your query based on a find with a dataProvider based on a modelSearch ..
public function actionView($id) {
$searchModel = new UrCommentSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
$dataProvider->query->andWhere(['IsDeleted' => 0]);
$dataProvider->pagination->pageSize=15;
return $this->render('view', [
'model' => $this->findOneModel($id),
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
and for view.php
<?php
echo ' <h1>User : ' . $model->userName . '</h1>';
echo '<h2>Comments</h2'>,
echo ListView::widget([
'dataProvider' => $dataProvider,
'itemView' => '_comment',
]);
where _comment is a partial view of you comment layout .,.
then in _comment.php you can simply
<?=$model->id;?>
<?=$model->text;?>