Clistview Update

Hi,

I would appreciate help with my problem.

I have a CListView to show uploaded files inside a CActiveForm:


<?php 

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

		    'dataProvider'=>$arrayDataProviderAttList,

		    'itemView'=>'_attList',

		    'id'=>'attList',

		     ));

?>

with script in form source code:


<?php

Yii::app()->clientScript->registerScript('ajaxUpdate',

"

//javascript function to update the listview using ajax

function updateItemList(){

    $.fn.yiiListView.update('attList');

    return false;

}


", CClientScript::POS_READY);

?>

and _attList as follows:


<?php 

echo $data->FileName;

echo $data->Size;

echo CHtml::ajaxLink('Delete',array('deleteAttachment','attID'=>$data->ID),

                array(	'type'=>'POST',

                		'success'=>'function(){updateItemList()}'

                	  ),

                array('confirm'=>'Really want to delete item?',

                    'id'=>'delete-'.$data->ID));  

?>

In my controller function, actionDeleteAttachment, I delete attachment and try to send back updated data. Unfortunatelly, I was not able to get the right syntax how to return changed $arrayDataProviderAttList for CListView…

Could someone please advice me?

Thank you for your help.

Hi flowerlee,

The sequence should be like this:




1) Client

      Delete Attachment Ajax Link

2) Server

      Delete Attachment Action

          delete the attachment file

          return success

3) Client

      Delete Attachment Ajax Link

          success

              updateItemList()

                  $.fn.yiilistview.update

                      calls the current url to update the list

4) Server

      Currenet Url

          renders the whole page including the list view content

5) Client

      $.fn.yiiListView.update

          success

              updates only the list view content



If you have problem in implementing #2, note that you don’t have to send back the updated content of the list there. Just delete the attachment file and, there’s nothing more to do.

See the delete action of the gii-generated controller code. It just ends silently when it is for ajax call. (The delete button of the grid view in the admin page follows almost the same sequence as stated above.)

$.fn.yiiListView.update calls by default the current url to update the list content.

This url should return the html that contains the content of the list. $.fn.yiiListView.update will scan the html and use only the content of the list to update the list.

You may optionally define the dedicated url by specifying ‘ajaxUrl’ property, in which you can render only the content of the list using renderPartial.

[EDIT]

One more thing to note.

IMO, you would be better not to use CHtml::alaxLink in the content which will be updated by ajax. It may work when the page has been loaded for the first time, but will stop to function after an ajax update.

I would write an event handler manually.




// _attList.php

echo CHtml::link('Delete', array('deleteAttachment', 'attID'=>$data->ID), array('class'=>'del_att'));

// _form.php

$csrfTokenName = Yii::app()->request->csrfTokenName;

$csrfToken = Yii::app()->request->csrfToken;

Yii::app()->clientScript->registerScript('delete_attachment', "

jQuery(document).on('click', 'a.del_att', function(){

  if(!confirm('Really want to delete item?')) return false;

  jQuery.ajax({

    'type' : 'POST',

    'url' : jQuery(this).attr('href'),

    'data' : {

      '$csrfTokenName' : '$csrfToken',

    },

    'success' : function(){

      updateItemList();

    }

  });

  return false;

});

");



This is basically the same script which Yii will generate for "Delete" button of a CGridView.

Thank you for your answer. I tried the second approach you suggested. I still have problem with number 4 of the sequence, that is rendering the whole page including the list view content.

Actually this was what I wanted to avoid, since I want the form remain filled but without submitting when attachment delete is performed.

My whole idea is form with few text fields and CMultiUpload widget. User fills it and may add some attachments. After he submits, attachments are saved to database and server side validation of fields as well as attachments is performed. If valiation fails, he gets warning and form with original data is rendered, as well as list of his attachments. This is the point where I need to implement the possibility of attachment deleting. Therefore I ask, isn’t it possible to update only this CListView but to keep the rest of the form unchanged? Or do I have to get filled data to server and back to client each time user deletes some attachment of the list?

Thank you for any advice and time spent

Oh, mistake.

No comma there.




    'data' : {

      '$csrfTokenName' : '$csrfToken'

    },



Well, $.fn.yiiListView.update won’t update anything but the CListView by default, even when you have rendered the whole page as the response. So when the other elements in the form got changed, then it’s not by $.fn.yiiListView.update.

OK now after I click Delete link, the item actually gets deleted and I see loading image of CListView.

But the list is empty.

What should I change in my controller (or elsewhere) to get the current list and sent it properly to the form?

Hmm, maybe you have to check the logic in the model and/or controller to get $arrayDataProviderAtt.

Allright…

I have




public function actionDeleteAttachment($attID)

{

                // delete selected attachment

		if(isset($attID))

			FaqFormAttach::model()->deleteByPk($attID);	

		

                // get updated list of attachments

		$arrayDataProviderAttList = $this->listAttachment();


                // return it

		return $arrayDataProviderAttList;

}



I’m sure I have problem with how to return it…

Dear Friend

Here we have one simple implementation.

Check whether it is helpful in your case.

I have a model.

[b]Item/b.

_view.php




<div class="view">


	<b><?php echo CHtml::encode($data->getAttributeLabel('id')); ?>:</b>

	<?php echo CHtml::link(CHtml::encode($data->id), array('view', 'id'=>$data->id)); ?>

	<br />


	<b><?php echo CHtml::encode($data->getAttributeLabel('name')); ?>:</b>

	<?php echo CHtml::encode($data->name); ?>

	<br />

<!--Added a button and assigned a unique id and assigned a class-->


    <?php echo CHtml::button("Delete",array('id'=>$data->id,'class'=>'button'));?>

</div>



index.php




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

	'dataProvider'=>$dataProvider,

	'itemView'=>'_view',

	'id'=>'itemList'//assigned a id for list container.

)); ?>


<?php

//the following script should be registered in index.php rather than _view.php.

//It is going to persist across multiple pages when we are using pagination by ajax.

Yii::app()->clientScript->registerScript("delete",'

	

	$("body").on("click",".button",function(){

		if(confirm("Do you really want to delete this item?"))

			$.fn.yiiListView.update("itemList", {data:{id:$(this).attr("id")}}) ;

		

		});


');



ItemController.php




public function actionIndex()

{   

	if(isset($_GET['id']))

	         Item::model()->deleteByPk($_GET['id']);

	

        $dataProvider=new CActiveDataProvider('Item');

	$this->render('index',array(

		'dataProvider'=>$dataProvider,

		));

}



Regards.

Thank you very much, that helped me to understand:)