Yii Ajaxlink To Delete Child: Duplicate Event Handler

Hi all,

I have two models Item and Field: Item has many Fields, and each Field belongs to an Item.

When viewing a single Item(i.e. item/view/79), I have added a partial view file called _itemFields.php that displays a list of Fields(with no widget, display is custom) belonging to the item being viewed, and an ajaxLink that I need to have for users to delete individual Fields from an item.

So in my Item Controller I created a new deleteField action and got the ajaxLink working to delete a Field, and refresh the _itemFields partial view model data. Unfortunately, the ajaxLink’s only seem to work once, and after the partial view has been refreshed, the ajaxLinks no longer work properly and a js console error is returned(see below). I’m a bit lost in this problem, and Hopefully some of you more experienced yii developers can help show me where I am going wrong.

Here’s the new actionDeleteField from Item Controller:




public function actionDeleteField()

{

 	if(isset($_POST['id']) && isset($_POST['ajax']) && $_POST['ajax']=='delete')

 	{			

	$field = Field::model()->findByPk($_POST['id']); // load field that user wants to delete


	$model = $field->item; // lazy load parent Item for partial view file


	$field->delete(); // delete field


	$this->renderPartial('_itemFields', array('model'=>$model), false, true); // pass parent Item back into _itemFields, fourth param set to refresh scripts


	Yii::app()->end();

 	}

}



Here is the relevant code from the views/item/view.php file:




<div class="item" id="item-<?php echo $model->id; ?>">

	

	<h1>View Fields for: <?php echo $model->title; ?></h1>

	

	<div class="content">

		

		<div class="fields">

			<?php $this->renderPartial('_itemFields', array('model'=>$model)); ?> // passes parent model into partial view to load children

		</div>

	

	</div><!-- /.content -->

	

</div><!-- /.item -->



And my views/item/_itemFields.php file:




<?php	

	foreach($model->fields as $field)

	{

?>

	<div class="field row" id="field-<?php echo CHtml::encode($field->id); ?>">

		

		<div class="lt">

			<b><?php echo CHtml::encode($field->name).": "; ?></b>

		</div>

		

		<div class="rt">

			<?php echo CHtml::encode($field->value); ?>

			

			<?php // delete link

				echo CHtml::ajaxLink(

		    		'Delete',

		    		CController::createUrl('item/deletefield'),

		    		array(

					'type'=>'POST',

					'data'=>array(

						'id'=>$field->id,

						'ajax'=>'delete',

					),

					'replace'=>'.fields',

		    		),

		    		array(

					'confirm'=>'Are you sure you want to Delete this Field?',

					'class'=>'ajaxDelete'

		    		),

				); 

				

			?>

		</div>

	</div>

<?php

	}

?>



To review, the ajaxLink works exactly as expected the first time: you click the link, the field gets deleted, and the partial view is refreshed with the new data set. If I try to click the link again, I get a duplicate ‘confirm’ messages(two of them) from the ajaxLink, and the js console error shown below:

[color="#FF0000"]POST http://localhost:888…tem/deletefield 500 (Internal Server Error) [/color]

Here are a couple of resources that helped me get to where I am:

http://www.yiiframework.com/wiki/49/

http://www.yiiframew…-renderpartial/

Thanks!

Ben,

Try replacing the line


'replace'=>'.fields'

with


'update'=>'.fields'

The replace option will remove the item selected (in this case the fields div) and replace it with the response. Update will replace the content inside the selected tag. From looking at your view it appears that this is what you want to do.

You are likely getting the HTTP 500 error because the old content is not being replaced and therefore the ajax call is bound twice and the ajax call is being made twice, resulting in an attempt to call an attribute on a null result.

Hey Zane,

Thanks for posting, that was definitely a step in the right direction: but, I’ve still got this other interesting issue, so let me describe what’s happening right now.

If I load the item/view/id and click on a delete link for a field, I get one expected confirm alert, the Field is deleted and the partial view is updated with the new data set. ("HURRAY!" I thought)

Now if I try to click on another delete link, I get one expected confirm alert, then one duplicate confirm alert("@$%!"), and the field is deleted, new data is displayed.

When I click on a third delete link, I get the one expected confirm alert, and now TWO unexpected confirm alerts, but still the field is deleted, and the view is properly updated.

Each time I click a delete link, I seem to get an extra confirm alert message, and an extra internal server error 500, matching each extra confirm alert, appended to the display. I honestly don’t have a clue why that would be myself: any thoughts Zane? Anyone?

Thanks!

I’ve found the answer to my problem in the first example of the wiki article comment linked to below:


array('id'=>'uniqueId', 'live'=>false)

http://www.yiiframew…request/#c10531

From what I understand, my ajaxLink’s work now because adding a unique id makes each link uniquely identifiable, and setting the “live” htmlOptions to false(api link below) will bind the event handlers directly to each unique link.

[/size]

http://www.yiiframew…ntChange-detail

Working views/item/_itemFields.php




<?php    

	foreach($model->fields as $field)

	{

?>

	<div class="field row" id="field-<?php echo CHtml::encode($field->id); ?>">

    	

		<div class="lt">

			<b><?php echo CHtml::encode($field->name).": "; ?></b>

		</div>

    	

		<div class="rt">

			<?php echo CHtml::encode($field->value); ?>

    		

			<?php // delete link

				echo CHtml::ajaxLink(

    				'Delete',

    				CController::createUrl('item/deletefield'),

    				array(

					'type'=>'POST',

					'data'=>array(

						'id'=>$field->id,

						'ajax'=>'delete',

					),

					'update'=>'.fields', // update div.fields data, don't 'replace' it with the new data

    				),

    				array(

					'confirm'=>'Are you sure you want to Delete this Field?',

					'class'=>'ajaxDelete',

                                        'id'=>'delete-'.$field->id, // set a unique id

                                        'live'=>false, // directly bind event handler to this unique link        			

                                      ),

				); 

    			

			?>

		</div>

	</div>

<?php

	}

?>



Zane, thanks again for your tip[size="2"] and hopefully this helps someone else out there. [/size]