I am trying to make an Ajax GridView using Pjax. Everything is working fine except the view, update and delete buttons are not AJAX. The code is:
<?php yii\widgets\Pjax::begin(['id' => 'demo']); ?>
<?= GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'id',
'name',
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
<?php yii\widgets\Pjax::end(); ?>
The problem is that the links for delete, view and update have the attribute data-pjax=0 which disables AJAX functionality. I cant find out how to set it too data-pjax=1.
You must do like below:
For Delete Action
1- Change your delete action like below:
public function actionDelete($id) {
$this->findModel($id)->delete();
if (Yii::$app->getRequest()->isAjax) {
$dataProvider = new ActiveDataProvider([
'query' => ModelName::find(),
'sort' => false
]);
return $this->renderPartial('index', [
'dataProvider' => $dataProvider
]);
}
return $this->redirect(['index']);
}
2- In your grid view:
['class' => 'yii\grid\ActionColumn',
'buttons' => [
'delete' => function ($url, $model) {
return Html::a('<span class="glyphicon glyphicon-trash"></span>', $url, [
'title' => Yii::t('yii', 'Delete'),
'data-pjax'=>'w0',
]);
}
]
],
Now, it works with Pjax.
Notes
My code in deleteAction() may decrease performance. You can write your own.
w0 usually is the default id of PJax. You can add an id to PJax and write it there instead.
This is the same for Update and View, But you need to change the way you show your update and view views.
This is highly recommended to take a look at Yii2's official PJax document: http://www.yiiframework.com/doc-2.0/yii-widgets-pjax.html
Related
I want to apply validation rules only for the input fields that are not empty (not required) for the URL
For example,
If I submit a form and the input is empty, I got a validation error "Instagram Link must be valid URL.", However, I want it without requiring,
and if the input is not empty, I want to apply the rule "valid_url"
How can we fix it?
if (!$this->validate([
'instagram' => [
'rules' => 'valid_url',
'errors' => [
'valid_url' => 'Instagram Link must be valid url.',
],
],
])){
return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
}
I tried with a permit_link rule, but if I submit it (with an input value like 'mylink' (which is not a valid_url)), it will accept it, but it should not.
Please check the following images and the code:
A form HTML
Result after clicking on edit button
<?= form_open('/settings/edit/1', ['id' => 'setting-form']); ?>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<?= form_label('Instagram'); ?>
<?= form_input(['name' => 'instagram', 'class' => 'form-control', 'id' => 'instagram', 'placeholder' => 'Enter instagram link', 'value' => old('instagram', $setting->instagram)]); ?>
</div>
</div>
</div>
<button type="submit" class="btn btn-dark">Edit</button>
<?= form_close(); ?>
public function edit($id)
{
if (!$this->validate([
'instagram' => [
'rules' => 'permit_empty|valid_url',
'errors' => [
'valid_url' => 'Instagram Link must be valid url.',
],
],
])) {
return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
}
die('submitted');
}
It should display "Instagram Link must be valid url" and not "submitted",
first
Use separate variable $rules like this :
$rules = ['data' => 'require']
Then
check if $this->request->getVar("instagram"); is empty / is true or etc.. then set it on the $rules
finally
Do Something like this :
$rules = ['extra_data' => 'require'];
if(!empty($this->request->getVar("instagram"))
$rules["instagram"] = "valid_url";
if ($this->validate(rules){
//do something ...
}else {
//do something ...
}
I just noticed that the following examples:
"mylink", "mylink.com", "https://www.mylink.com"
will consider correct for the rule valid_url in Codeigniter (No errors),
While: "https:://www.mylink.com", "mylink#" will apply the validation and the error is applied.
i'm trying without success to add an image inside a Navbar menuItem.
It works fine in the brandLabel
But doesn't work on anoter menu item
(I Want to display the logged user image near his name)
I Tryed several times but doesnt seem to make it work,
Would apreciate your help please...
The Code is this:
<?php $this->beginBody() ?>
<div class="wrap">
<?php
NavBar::begin([
'brandLabel' => Html::img('#themes'.'/siteImages/Logo.jpg', ['alt'=>Yii::$app->name]),
'options' => [
'class' => 'navbar-default navbar-fixed-top',
],
]);
// display Login page to guests of the site
if (Yii::$app->user->isGuest) {
$menuItems[] = ['label' => Yii::t('app', 'Login'), 'url' => ['/site/login'],
'options' => [
'class' => 'navbar-right',
],];
}
else
{
// Show sales content to sales+ users
if ( Yii::$app->user->can('useSalesContent'))
{
$menuItems[] = ['label' => Yii::t('app', 'Sales'),
// 'class' => "pull-left",
'url' => Yii::$app->homeUrl,
'linkOptions' => ['id' => 'sales',
'class' => 'navbar-left',
],
];
// Show Admin content to manager+ users
if (Yii::$app->user->can('useAdminContent'))
{
$menuItems[] = ['label' => Yii::t('app', 'Administration'),
'url' => Yii::$app->homeUrl,
'linkOptions' => ['id' => 'admin'],
'options' => [
'class' => 'navbar-left',
],];
}
// display Logout to logged in users
if (!Yii::$app->user->isGuest) {
$menuItems[] =
[
'label' => Yii::t('app', 'Logout'). ' (' . Yii::$app->user-
>identity->username . ')',
'url' => ['/site/logout'],
'linkOptions' => ['data-method' => 'post']
//****** This is where I want the user image to be shown ****//
];
}
}
// echo navbar with selected items
echo Nav::widget([
'options' => ['class' => 'navbar-nav navbar-right'],
'items' => $menuItems,
]);
NavBar::end();
?>
<div class="container">
<?= Alert::widget() ?>
<?= $content ?>
</div>
endBody() ?>
Provided the user model has an attribute imageUrl it would be accessible through:
Yii::$app->user->identity->imageUrl
This would become something like:
If you would like to add it to the logout button:
$menuItems[] = [ 'encode'=>false, label' => Yii::t('app', 'Logout'). ' (' . Yii::$app->user- >identity->username . ') ' . Html::img(Yii::$app->user- >identity->imageUrl), 'url' => ['/site/logout'], 'linkOptions' => ['data-method' => 'post']];
make sure you include 'encode' => false,
To add it as a separate item (for instance, to give it a different link):
$menuItems[] = [ 'encode' => false, 'label' => Html::image(Yii::$app->user- >identity->imageUrl)];
Edit:
Make sure you include the Html with a use statement in your view, or provide the full namespace declaration with Html class.
I have a same field in foreach loop like below
foreach ( $subCategoryData as $k => $val) {
<?= $form->field($model, 'sub_category', ['template' => '{input}'])->textInput(['maxlength' => 255, 'class' => 'form-control required section_name', 'name' => "Category[sub_category][$k][name]"]) ?>
} ?>
I have ajax validation with custom method it is working fine.
But it is Working with only first input. Because it has same ID.
But when I changed it with 'inputOptions' => ['id' => 'myCustomId'] and make it unique with below and my ajax validation is not called.
foreach ( $subCategoryData as $k => $val) {
<?= $form->field($model, 'sub_category', ['template' => '{input}','inputOptions' => ['id' => "category-sub_category_".$k]])->textInput(['maxlength' => 255, 'class' => 'form-control required section_name', 'name' => "Category[sub_category][$k][name]"]) ?>
}
I have seen this solution here
https://github.com/yiisoft/yii2/issues/7627
and also seen this https://stackoverflow.com/a/28460442/2286537
But nothing work
can anyone help me ?
Your question is different from the posts you introduced.
You should use loadMultiple.
Example:
if (\Yii::$app->request->isAjax) {
if (\yii\base\Model::loadMultiple($model,\Yii::$app->request->post())) {
\Yii::$app->response->format = Response::FORMAT_JSON;
echo json_encode(ActiveForm::validateMultiple($model));
\Yii::$app->end();
}
}
if ( \yii\base\Model::loadMultiple($model, Yii::$app->request->post()) && \yii\base\Model::validateMultiple($model)) {
foreach ($model as $models) {
$models->save(false);
}
in view:
<?php $form = ActiveForm::begin([
'enableAjaxValidation' => true,
]);
I want to use PJax in Yii Grid View, not with the associative filter that comes inside the Grid View, but with the Search Filter that's outside it, so it can filter the results inside.
Here is the source of the index file:
<div class="cars-index">
<h1><?= Html::encode($this->title) ?></h1>
<?php echo $this->render('_search', ['model' => $searchModel]); ?>
<p>
<?= Html::a('Create Cars', ['create'], ['class' => 'btn btn-success']) ?>
</p>
<?= GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
'id',
'name',
['attribute' => 'code',
'label' => 'Colour',
'format' => 'raw',
'value' => 'colour',
'contentOptions' => function ($model, $key, $index, $column){
return ['style' => ' text-align: center; width: 100px;color:white;background-color:#'. $model -> code];
},
'headerOptions' => ['style' => 'text-align: center;'],
],
'price',
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
Am I supposed to create an active form just for the part I want to filter? Or is there another way?
If You can't simply add the filter to you table like this
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
I suggest you use a proper action and a proper search function called by submit based on a specified active form
for action form eg:
<?php $form = ActiveForm::begin([
'id' => 'search-form',
'method' => 'post',
'action' => ['controller/yourAction']
]); ?>
in the controller
$model = new yourActiveForm();
if ($model->load(Yii::$app->request->post()) ) {
$dataProvider = $searchModel->search( [ 'yuorSearchModel'=> ['your_att1' => $model->yourValue1]]);
}
then your render
Conforming to yii2 doc
Pjax only deals with the content enclosed between its begin() and
end() calls, called the body content of the widget. By default, any
link click or form submission (for those forms with data-pjax
attribute) within the body content will trigger an AJAX request. In
responding to the AJAX request, Pjax will send the updated body
content (based on the AJAX request) to the client which will replace
the old content with the new one. The browser's URL will then be
updated using pushState. The whole process requires no reloading of
the layout or resources (js, css).
You may configure $linkSelector to specify which links should trigger
pjax, and configure $formSelector to specify which form submission may
trigger pjax.
You must add the
<?php Pjax::begin(); ?>
.... your active form
<?php Pjax::end(); ?>
and configure the proper $linkSelect and $formSelector
In your filter view:
<div id="myFilter">
<?php $form = ActiveForm::begin([
'id' => 'myFilterForm',
'method' => 'post',
'action' => [...],
]); ?>
...
</div>
And make sure you render filter between Pjax::begin and Pjax::end
Yet here comes the trick. If your server does not respond within default timeout, Pjax gets ignored and page reloaded, so make sure the timeout is big enough:
<?php Pjax::begin([
'id'=>'myGrid',
'timeout' => 10000, // <------------ THIS !!!!!!!
'formSelector' => '#myFilterForm'
]); ?>
<?= $this->render('myFilter', ['model' => $searchModel]); ?>
<?= GridView::widget([
...
]); ?>
<?php Pjax::end(); ?>
Also in your controller, you might want to "reset" the search model, so only data from the request used are attributes actually used by search:
public function actionSearch()
{
$searchModel = new MySearch();
if ($searchModel->load(Yii::$app->request->post())) {
$searchModel = new MySearch(); // "reset"
$dataProvider = $searchModel->search(Yii::$app->request->post());
} else {
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
}
return $this->render('search', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
Hope this helps. Cheers!
I'm just learning Yii a few days ago to developer a website for company. Now i have some issue with Yii pagination and i really need your help.
Currently i can make Yii pagination. However, i need to create a button besides pagination area. Everytime, i click that button, it will call ajax to load next page or previous pages (if current page is last page).
Here is my model:
public function getListDesc()
{
$arrPlace = array(0 => '--- --- --- ---');
$criteria=new CDbCriteria;
$criteria->select='t.*,pi.path path';
$criteria->join='JOIN places_images pi ON t.id=pi.places_id';
$criteria->group = 't.id';
$criteria->compare('t.deleted', '<>1', false);
$criteria->compare('t.status',1);
$criteria->compare('outlet','Outlet 1');
$criteria->order = 't.id DESC';
return new CActiveDataProvider('Places', array(
'criteria'=>$criteria,
'pagination' => array(
'pageSize' => 2
)
));
}
Here is a part of my index page which is call that model:
<?php
$this->widget('zii.widgets.CListView', array(
'id' => 'places-list-right',
'dataProvider'=> Places::model()->getListAsc(),
'summaryText'=>'',
'pager' => array(
'header' => '',
'prevPageLabel' => '<<',
'nextPageLabel' => '>>',
),
'itemView'=>'_fea_oulet',)
);
?>
Here is _fea_oulet.php file:
<div class="place_img" id="<?=$data->id?>">
<div class="plusimage">
<a href="javascript:void(0);" onclick="randnew();">
<img alt="<?=$data->id?>" src="<?php echo Yii::app()->request->baseUrl; ?>/images/9life-show-more-images.png" style="border:none;border-radius:0;-webkit-border-radius: 0; -moz-border-radius:0">
</a>
</div>
<?php echo CHtml::image("timthumb.php?src=".$data->path."&w=294&h=294&zc=1&q=100",$data->title);?>
<div class="featitle">
<h3><span><?php
if(strlen($data->title) > 30) {
echo CHtml::encode(mb_substr($data->title,0,30,'UTF-8')) . '...';
}
else{
echo CHtml::encode($data->title);
}
?></span>
<img src="<?php echo Yii::app()->request->baseUrl; ?>/images/9life-show-more-green.png" style="border:none;border-radius:0;-webkit-border-radius: 0; -moz-border-radius:0">
</h3>
</div>
</div>
Any help are appreciates.
Thanks,
You can override CLinkPager class and use your own implementation MyLinkPager in your CListView widget's call specifying its pager property like this:
$this->widget('zii.widgets.CListView', array(
'id' => 'places-list-right',
'dataProvider' => Places::model()->getListAsc(),
'summaryText' => '',
'pager' => array(
'class' => 'MyLinkPager',
'header' => '',
'prevPageLabel' => '<<',
'nextPageLabel' => '>>',
),
'itemView' => '_fea_oulet'
));
run() method of CLinkPager is the place where pager buttons' rendering happens so you can override this method directly. Or you can override createPageButtons() method by adding your custom button to $buttons array if you want to see it along with other page buttons.