Hi All,
I thought of sharing something that I just made. I needed a pager in Yii that would work something like lazy loading. I scoured the internet but didn’t find anything suitable. Then I came across few articles which would work as the basis for lazy loading. To make the pager, I did the following:
-
extended CBasePager
-
extended CListView
-
created a view which just showed items
-
modified the controller function to return paginated data with ajax
The articles I have followed are:
Extending CListView
Partial rendering in CListView
- Creating new Pager:
I extended CBasePager class just to create a LOAD MORE button. I have put a span element instead of a tag since a tag would refresh the grid every time it is clicked. The code is as follows:
<?php
/**
* class TOCPager
* - extend pager to make pager for TOC for content
* - add
*/
class exPager extends CBasePager
{
public function run()
{
$currentPage = $this->currentPage;
$pageCount = $this->pageCount;
if($currentPage < $pageCount)
{
list($controller, $action) = explode('/', Yii::app()->urlManager->parseUrl(Yii::app()->request));
$theUrl = Yii::app()->request->url;
//var_dump($this->getOwner());
echo '
<div class="load-msg">
<input type="hidden" id="pgNumber" value="'.($currentPage+1).'"/>
<span id="paginator">LOAD MORE...</span>
</div>
';
$cs = Yii::app()->getClientScript();
$script = '
$("#paginator").click(function(e)
{
var containerElement = $(this).parent().parent().parent().attr("id");
var itemsList = $(this).parent().parent().prev();
var nextPage = $(this).prev().val()*1;
var pageCount = '.$pageCount.'*1;
var pgNumber = $(this).prev();
$.ajax({
url:"'.$theUrl.'?ajax="+containerElement+"&page="+(nextPage+1),
success:function(returnData)
{
$(itemsList).append(returnData); //append the content
pgNumber.val(nextPage+1);
if(pgNumber.val() == pageCount)
$("#paginator").parent().attr("style", "display:none;");
}
});
});
';
$cs->registerScript('#script', $script, CClientScript::POS_READY);
}
}
}
- Next, I extended CListView just to return the items, not with wrapping tags. The code is as follows:
<?php
Yii::import('zii.widgets.CListView');
class PlainCListView extends CListView
{
public $preItemsTag = '';
public $postItemsTag = '';
public function renderItems()
{
echo $this->preItemsTag."\n";
$data=$this->dataProvider->getData();
if(($n=count($data))>0)
{
$owner=$this->getOwner();
$render=$owner instanceof CController ? 'renderPartial' : 'render';
$j=0;
foreach($data as $i=>$item)
{
$data=$this->viewData;
$data['index']=$i;
$data['data']=$item;
$data['widget']=$this;
$owner->$render($this->itemView,$data);
if($j++ < $n-1)
echo $this->separator;
}
}
else
$this->renderEmptyText();
echo $this->postItemsTag."\n";
}
public function run()
{
$this->renderContent();
}
}
- Thirdly, I created a small view that uses previously created PlainCListView for showing the list. An example of the view is as follows:
<?php
$this->widget('application.widgets.PlainCListView', array(
'dataProvider'=>$posts,
//'afterAjaxUpdate'=>'clickEvents',
//'ajaxType'=>'POST',
'itemView'=>'_post',
'viewData'=>array('userForumStatus'=>$userForumStatus, 'isLocked'=>$isLocked),
'summaryText'=>'',
'id'=>$listID,
'template'=>'{items}',
));
?>
- Lastly, in the controller, I have followed the idea presented here. My sample code is as follows:
if(Yii::app()->request->isAjaxRequest && isset($_GET['ajax']) && $_GET['ajax'] === $listID)
{
$this->renderPartial('_posts_list_nopager', array(
'posts' => $posts,
'listID' => $listID,
'userForumStatus'=>$userForumStatus,
'isLocked'=>isset($parentForum['locked'])?$parentForum['locked']:0
));
Yii::app()->end();
}
So, when you run everything, you will get a pager ‘LOAD MORE’ at the bottom of the list. If you click it, additional rows/items will be appended to the existing items block.
I hope this is helpful to everybody. I had hell of a time searching for right materials for this.