Developing custom Grids and ListViews for my new CMS I was facing a small challenge: If I was to update/delete/batch delete items of my Grid, how would I return to the current page view?
I know there a couple of extensions out there, but I do extensive use of AJAX into my applications. Once a user logs in, the rest in my CMSs are pure AJAX, so the extensions where of no HELP in this scenario.
If you check at the parameters of the pagers you see the parameter name to be on the format of: Modelname_page.
In order to solve the issues (I wont expose the solution of the custom widgets and components because they have to do with the CPagination object) of returning back to the current page displayed I did this:
// in my globals.php -this file is imported on index.php
/**
* Returns the named HTTP parameter.
* This is the shortcut to Yii::app()->request->getParam($name)
*/
function getParam($name, $default=false){
return Yii::app()->request->getParam($name, $default);
}
/**
* Returns an array of matched Page parameters
* based on the Model name given
*/
public function getPaginationParam( $modelName ){
// format name appropiately *no misstyping errors allowed*
$modelName = ucfirst(strtolower($modelName));
// return the param
return getParam($modelName.'_page') ? array($modelName.'_page'=>getParam($modelName.'_page')):array();
}
Once I have that function, I can find out whether a pagination parameter was submitted or not. Let's imagine a user clicks on the delete button and the actionDelete of the Bogus controller is called, I would like after deletion to return to the admin display of Bogus Models and to continue on the same page.
public function actionDelete(){
if(Yii::app()->request->isPostRequest)
{
// we make use of getParam -see above
// we should check whether the param
// returns false or not!!! This is too simple
$this->loadModel( getParam('id') )->delete();
//
// lets get the page params of bogus if any
$params = getPaginationParam('bogus');
//
// create the url appropiately
$route = $this->createUrl('admin',$params);
//
// redirect to admin and finish
$this->redirect($route,true);
}catch(Exception $e){
....
Easy right? Now, what about update? Well, in my case, what I did, is to include a hidden field into the form if there is a page parameter and on submission i do the same on the actionUpdate as I did on the actionDelete of the controller.
put all logic in actionAdmin
A simpler way to set & retain page number is to put all the logic in actionAdmin. Even better, move the actionAdmin to a parent class for all your controllers; or change the Gii generation templates so all controllers get this code:
// at the top of every controller $this->modelClass = '<modelName>'; // the data model of this controller public function actionAdmin { $pageParam = ucfirst($this->modelClass). '_page'; if (isset($_GET[$pageParam])) { $page = $_GET[$pageParam]; Yii::app()->user->setState($this->id.'-page',(int)$page); } else { $page=Yii::app()->user->getState($this->id.'-page',1); $_GET[$pageParam] = $page; } ... }
the only problem is with the First (<<) button, and Previous (<) button on page 2, which do not contain explicit page 1, just the URL for the basic grid view. Without the patches below, these buttons will not work.
Fixing this involves the following:
class MyActiveDataProvider extends CActiveDataProvider { private $_pagination; public function getPagination() { if($this->_pagination===null) { //$this->_pagination=new CPagination; $this->_pagination=new MyPagination; if(($id=$this->getId())!='') $this->_pagination->pageVar=$id.'_page'; } return $this->_pagination; } }
class MyPagination extends CPagination { public function createPageUrl($controller,$page) { $params=$this->params===null ? $_GET : $this->params; // if($page>0) // page 0 is the default $params[$this->pageVar]=$page+1; // else // unset($params[$this->pageVar]); return $controller->createUrl($this->route,$params); } }
public function search() { $criteria=new CDbCriteria; .... return new MyActiveDataProvider(get_class($this), array( 'criteria'=>$criteria, )); }
Modification
I've used the example here without creating MyActiveDataProvider class.
I've only modified the actionAdmin method like this, up to now, it works well:
// at the top of every controller $this->modelClass = '<modelName>'; // the data model of this controller public function actionAdmin { $pageParam = ucfirst($this->modelClass). '_page'; if (isset($_GET[$pageParam])) { $page = $_GET[$pageParam]; Yii::app()->user->setState($this->id.'-page',(int)$page); } else { // If no param for page number but param grid exists if(isset($_GET['ajax']) && $_GET['ajax'] == $this->modelClass . '-grid') { // We're on the first page $page = 1; } else { $page=Yii::app()->user->getState($this->id.'-page',1); $_GET[$pageParam] = $page; } } ... }
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.