Problem with Pagination in CListView by Ajax request

I apologize if this has been answered but I have searched and searched and nothing I have found has helped…

I have a program with the following flow:

Database of Customers. I search it and generate a result set

Display the result set in CGridView

Select the Customers I want to view in detail

Ajax Button calls the ‘customers/viewSelected’ controller action.

That controller action queries the Customer database for the selected records and creates a data provider with pagination set to 1 per page

Print a CListView in another div on the same page as the CGridView that displays the first record, with the pager widget.

Everything works fine up until now. I get the first record displayed in full in the CListView, and the pager widget appears in the div with the correct number of pages. But when I click on a page link to get page 2 or page 3, I get a blank result. No data, no pager.

Here is the code for the ajaxButton at the bottom of the CGridView:




echo CHtml::ajaxButton('View Customers', 'viewSelected',

		array( 'type' => 'post',

			'data' => 'js:{ids:$.fn.yiiGridView.getSelection("customerListGrid")}',

			'update'=>'#custView' ));



Here is the controller customers/viewSelected:




	 public function actionViewSelected()

	 {

	 	if(Yii::app()->request->isAjaxRequest){

                	if(isset($_POST['ids'])) {

	 			$criteria=new CDbCriteria;

	 			$criteria->together=true;

	 			$criteria->with=array('leads','searches'); // ADD JOURNAL

	 			$criteria->addInCondition('t.id',$_POST['ids']);

	 			

	 			$pages=array('pageSize'=>1);

	 			

	 			$dataProvider=new CActiveDataProvider('Customers',array('criteria'=>$criteria,'pagination'=>$pages));

				$this->renderPartial('view',array('dataProvider'=>$dataProvider),false,true);

	 		}

	 	}

	 }



Here is the "view.php":




<h1>Customers</h1>


<?php 


$this->widget('zii.widgets.CListView', array(

	'dataProvider'=>$dataProvider,

	'ajaxUpdate'=>'#custViewPanel',

	'enablePagination'=>true,

	'itemView'=>'_view',


));

 ?>

I appreciate any help in getting this working. Also, as I am an amateur teaching myself through this, I welcome any observations on the code or general advice.

Thank you.

Have you looked at the ajax response? Is it returning anything?

Please check what the value of $_POST is during an ajax update.

When I click on a pager link, there is no ajax response.

So probably $_POST[‘ids’] is empty on ajax update, are you sure the vars are send as an array to the server?

I don’t really get how it works. When I click the button on my Grid view, it sends the array in an ajax request. The right search is run and the first result is sent to the List View. The paginator links just send a GET with “Customers_page=2” as the name->value pair. I think that is being sent to the customers/viewSelected controller action, which probably has no idea what to do with it, but I don’t know how to make the paginator send the right kind of request. Because, hasn’t the controller already run the query, retrieved all the results into the dataprovider and sent it to the view? Shouldn’t the paginator simply be flipping through an array in the dataprovider to pull out the next instance? Why would it go back to the controller?

Hello !,

your code is a bit complicated and so many pieces aren’t shown here, so its difficult to help you.

BUT, dont worry, reading your question and understanding what’s your needs, then please follow

my code and your problem will be solved.

YOUR CONTROLLER:

please note: use your own DataProvider, i use an array based data provider for sample reasons.

the most important thing is the keyField, because the data provider uses this field on a CGridView when

a selection is fired.

in this action, when a POST is invoked then a selection is rendeder using a _view.php,

when this action is invoked using a GET method then a dataProvider is passed to the main view.php.




     public function actionViewSelected()

     {

     	 // sample data, put your own data coming from your own CActiveRecord

         $rawData = array();

         $rawData[0]['customerid']=1;

         $rawData[0]['name']='ana maria';

         $rawData[1]['customerid']=2;

         $rawData[1]['name']='john doe';

         //

		$dataProvider=new CArrayDataProvider($rawData, array(

		    'id'=>'sampledata',

			'keyField'=>'customerid', // very important field !!

		));

		// end sample data

		if(Yii::app()->request->isAjaxRequest)

		{

			// a POST call, will detail your selection

			//

        	if(isset($_POST['ids'])) {

        		$customerIdSelected = $_POST['ids'][0];

        		$selection = null;

        		foreach($rawData as $data){

					if($data['customerid'] == $customerIdSelected){

						$selection = $data;

						break;        	

					}		

        		}

            	$this->renderPartial('_view'

                	,array('data'=>$selection)

                    ,false,true

                );

        	}

		}

		else

		{

			// a GET call to this action will launch your view

			//

			$this->render('view',array('dataProvider'=>$dataProvider));

		}

	}




YOUR view.php file

it uses a CGridView, it allows a selection as a part of its features. You dont need to build your own

selection method.




<h1>Customers</h1>

<?php 

$this->widget('zii.widgets.grid.CGridView', array(

	'id'=>'customerListGrid',

    'dataProvider'=>$dataProvider,

	'selectableRows'=>1,

    'columns'=>array(

		array('name'=>'checked','class'=>'CCheckBoxColumn'),

        'customerid',

        'name',

    ),

));

echo CHtml::ajaxButton(

	'View Selected Customer', 'index.php?r=site/viewSelected',

	array( 'type' => 'post',

    	'data' => 'js:{ ids:$.fn.yiiGridView.getSelection("customerListGrid") }',

        'update'=>'#custView', 'error' =>'errortrap'));

 ?>

 <div id='custView'>...</div>



YOUR DETAIL VIEW: _view.php

this will show your record taken from your dataprovider in your action, rendered when your

action is called as a POST when you click your ajax button.




Your selection is:

<h3><?php echo $data['name']; ?> (<?php echo $data['customerid']; ?>)</h3>



Many thanks! Tomorrow with a fresh brain, I will work through this response and master it. I appreciate you taking the time to lay it out for me!

nice !hope it helps you.the first problem in your own code seems to be the CListView usage instead of a CGridView, nextyour ajaxButton tries to get the list selection using a CGridView function: $.fn.yiiGridView.getSelection (the CListView dont have a getSelection method in its javascript module, so, nothing is returned when you invoke it),a CGridView is a better choice in my opinion because this class has its own selection method as you can see in my code (the selectableRows attribute activate this feature, value 1 is single selection, 2 is multi and 0 is no selection enabled). The ajaxButton can obtain the selected item in the Grid (the array data provider has a special field named: keyField, is important because gridview uses this value to return the selected id) using the mentioned js function then pass the selected ID to an action using an ajax call via POST, the ajax result will be rendered into a _view.php and finally returned to your browser into a DIV.

I use CGridView for the list of customers, then use the CListView to show individual customer records. Technically, I should be using CDetailView instead of CListView, but I wanted to have the option of selecting more than one record from the CGridView and paging through them, one record at a time. CDetailView didn’t seem to work for that. CListView is a lot more flexible for formatting the display than is CGridView.

Hey Bluyell, I think I understand this now, but I have a further question: what happens if you have selectableRows => 2 and the user selects more than 1 row?

Yes !

0=no selection

1=select one record

2=select more than one.

http://www.yiiframework.com/doc/api/1.1/CGridView#selectableRows-detail

:-[

I tried to implement your solution using my CActiveDataProvider, but get no data out of the ajax request. I do not understand how the dataproviders work, so I am unable to make the conversion from an array dataprovider to an object dataprovider. Quoted below is what I tried to do:


	public function actionList()

	{


		$model=new Customers('csearch');


		if(Yii::app()->request->isAjaxRequest) {

                        // a POST call, will detail your selection

                        //

                	if(isset($_POST['ids'])) {

                var_dump($_POST['ids']); -----> this prints out the correctly received ajax request

                echo '<br />';

                        	$customerIdSelected = $_POST['ids'][0];

                        	$selection = null;

                        	foreach($model as $data){

                        var_dump($data); ----------------> result of this printout below

                        echo '<br />';	

                                        if($data->id == $customerIdSelected){

                                                $selection = $data;

                                                break;          

                                        }               

                        	}

                		$this->renderPartial('_view',array('data'=>$selection),false,true);

                	}

                }

                else {

                     

			

			$this->renderPartial('csearch',array('model'=>$model),false,true);

		}

	}

The result of var_dump($data):


int(0)

int(1)

int(0)

NULL

NULL

NULL

NULL

NULL

NULL

NULL

NULL

NULL

NULL

NULL

NULL

NULL 

Also, the pagination doesn’t even work in the original CGridView. When I click on a page number. the page refreshes with empty data.

I am very frustrated with all this. It should not be so difficult in a framework to make pagination work. It should not be such an arcane science that only the experts can figure it out. I find the documentation to be quite lacking. I feel like I could just write my own pagination code in less time than it will take to figure out how Yii’s “widgets” work, because there’s no explanation of mechanics in the documentation.

hey, dont desperate !

first, your selected ID comes when you call: “[size=2]$_POST[/size][color=#666600][size=2][[/size][/color][color=#008800][size=2]‘ids’[/size][/color][color=#666600][size=2]][0]” (not only: [/size][/color][size=2]$_POST[/size][color=#666600][size=2][[/size][/color][color=#008800][size=2]‘ids’[/size][/color][color=#666600][size=2]]…without the [0] part[/size][/color][color=#666600][size=2])[/size][/color]

[color="#666600"][size=2][b]

[/b][/size][/color]

1st. question:

when you push your button, please log here the echo for:


echo "[IDS=".$_POST['ids'][0]."]";

as i wrote here.

2nd question:

your CGridView presents data ? (i assume yes…)

One of the main problems I am having in understanding what is going on is that the documentation is confusing. Yii allows something to be done so many different ways, and the documentation jumps from one way to another, with the code examples being small and generally not in context. Makes it very hard to follow, much like having two or three jigsaw puzzles tossed on a table together.

I think the root of the problem is how I do the first search. Because nowhere did the docs give a coherent meta-view of the procedure for making a search form->dataprovider->view sequence, I looked here and there and put together my own procedure. By trial and error I got it to work, but it only works if the program goes through the sequence only once. I have deduced that when a view is paginated, getting the next page of results means stepping back through the controller->dataprovider->view sequence, and when you go back through the sequence I created a second time, it doesn’t work, because the whole sequence depends on the initial $_POST with the search form data being present, and it is no longer present.

I don’t understand how a dataprovider works. I’ve read the class references so I know all the properties and methods, but I don’t get how the system works. I also don’t understand how yii does pagination. When I click on Page 2, what does the system do? Why does it go back to the controller? Isn’t the data sitting in the dataprovider? Shouldn’t it just step through the data in the array?

So the answer to your second question is that when you click on a page link for more data, my CGridView is NOT presenting data.

The answer to your first question is: [IDS=10]array(1) { [0]=> string(2) "10" }

You said “first, your selected ID comes when you call: “$_POST[‘ids’][0]” (not only: $_POST[‘ids’]…without the [0] part)”

But my code already says: “$customerIdSelected = $_POST[‘ids’][0];” Is that not right?

Also, you used a CArrayDataProvider in your example. I am using a CActiveDataProvider. Can I step through it with a foreach loop like "foreach($model as $data)"?

I really appreciate your help. Thank you for the time you have put into this. I know you could be doing other things, and I am frustrated mostly with my inability to grasp the fragments and put them together into a coherent whole. You’ve been great.

Hey Bluyell, I got it working! You steered me in the right direction, and I was able to find the problem. I just had to go back to basics and rebuild the process from the ground up. Now I understand how the process works and I can use it correctly!

Thank you again for your time, I really appreciate it and it was of tremendous value to me! :)