Ajax update not working

I found these examples for updating a div using Ajax however my case is a bit different and I guess that might be the reason why it’s not working.

http://www.yiiframework.com/wiki/49/update-content-in-ajax-with-partialrender/

http://www.yiiframework.com/wiki/87/ajax-update/

In both cases above, link which updates the div is outside the div, e.g.


<div id="update-this"></div>


<div class="link">

    <?php echo CHtml::ajaxLink('clickMe', array('ajax'), array('update'=>'#update-this'));?>

</div>

In my case, the ajax link is contained within the div which need to be updated as shown below.


<div id="update-this">

    <div class="link">

        <?php echo CHtml::ajaxLink('clickMe', array('ajax'), array('update'=>'#update-this'));?>

    </div>

</div>

In my case, the controller function is getting called and functionality is being executed just fine however the div is not refreshed with new content.

To provide some context info, it’s like a moderation panel where admin is shown information for approval/rejection and on each selection, div is updated to show next information for moderation with updated ajax links since each information ID is different.

1 Like

I’m not sure why it don’t work.

Can you post more code: the whole view (or a larger part of it), and of course the controller part (the ‘clickMe’ action)?

By the way, do you mean you have many similar divs in your view with the same id?

Thanks for responding. It doesn’t have multiple div with same ID.

Here is the code.

Controller


	public function actionModerate() {

		$model = Post::model()->find(

									'status=:status AND user_id!=:user_id', 

									array(

										':status'=>Post::STATUS_PENDING,

										':user_id'=>Yii::app()->user->id

									)

		);

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

			'model'=>$model,

		));		

	}

	

	public function actionMod()

	{

		$post=Post::model()->findByPk($_POST['post_id']);

		

		$post->status = $_POST['status'];

		$post->moderator_id = Yii::app()->user->id;

		

		if($post->save()) {

			$model = $this->find('status=:status', array(':status='=>Post::STATUS_PENDING));

			$this->renderPartial('_mod',array(

					'model'=>$model,

				), 

				false, 

				true

			);

		}

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

	}

View (moderate.php)


<?php

$this->breadcrumbs=array(

	'Posts'=>array('index'),

	//$model->id,

);

?>

<div class="row">

	<div class="well">

		<div id="moderate-container">

			<?php $this->renderPartial('_mod', array('model'=>$model)); ?>

		</div>

		<div class="row">

			<!--  empty row for spacing -->

			<div class="span12">

			</div>

		</div>

		<div class="row">

			<div class="center">

				<img src="http://placehold.it/225x225"/>

			</div>

		</div>

	</div>

</div>

View (_mod.php)


<?php if($model!=null) { ?>

	<p class="post-contents">

	<?php echo CHtml::encode($model->content); ?>

	</p>

	<div class="story-footer">

		<p class="story-voting">

		</p>

		<p class="story-details">

			<?php

				$user = User::model()->findByPk($model->user_id);

				echo 'On ' . strftime('%m/%d/%Y at %I:%M %P', strtotime($model->created));

				echo ' - ';

				echo CHtml::link($model->category->name, array());

			?>

		</p>

		<p class="story-approval-btns center">

			<span class="moderate-yes">

				<?php 

						echo CHtml::ajaxLink('<i class="icon-ok icon-white"></i> Yes', 

							Yii::app()->createUrl('post/mod'), 

							array(

								'type'=>'POST',											

								'update'=>'#moderate-container',

								'data'=>array('post_id'=>$model->id, 'status'=>Post::STATUS_APPROVED),

								/*'success' => "function( data )

								{

									// handle return data

									$(\"#moderate-container\").html(data);

								}"*/										

							),

							array(

								'href' => Yii::app()->createUrl('post/moderate'),

								'class'=>'btn btn-success'

							)

						);						

				?>

			</span>

			<span class="moderate-no">

				<?php 

						echo CHtml::ajaxLink('<i class="icon-remove icon-white"></i> No', 

							Yii::app()->createUrl('post/mod'), 

							array(

								'type'=>'POST',											

								'update'=>'#moderate-container',

								'data'=>array('post_id'=>$model->id, 'status'=>Post::STATUS_REJECTED),

								/*'success' => "function( data )

								{

									// handle return data

									$(\"#moderate-container\").html(data);

								}"*/							

							),

							array(

								'href' => Yii::app()->createUrl('post/moderate'),

								'class'=>'btn btn-danger'

							)

						);						

				?>

			</span>

		</p>

		<span class="story-sharing">

			<!--  -->

		</span>	

	</div>

<?php } else { ?>

	<h2 class="center">Yay! No more pending posts for moderation.</h2>

<?php } ?>

I haven’t understood your goal with that code. You seem to render the same view as a result for the ajax call?

Anyway, have you tried a simpler output in ajax, like:


public function actionMod()

{

    // your code (comment out the renderPartial for the moment

    echo 'Here is the result';

}

…

<span class="moderate-no">

<?php 

    echo CHtml::ajaxLink('<i class="icon-remove icon-white"></i> No', 

        Yii::app()->createUrl('post/mod'), 

        array(

            'type'=>'POST',                                                                                 

            'update'=>'#moderate-container',

            'data'=>array('post_id'=>$model->id, 'status'=>Post::STATUS_REJECTED),

        ),

        array(

            // why the following line by the way?

            // 'href' => Yii::app()->createUrl('post/moderate'),

            'class'=>'btn btn-danger'

        )

    );                                              

?>

</span>

Yes, I have tried simple ajax call and it’s working fine. Regarding the logic of using same view for update, the ajax links need to be reloaded as they will be tied to different post id so ajax links should be within the same view which will be refreshed. If you have any suggestions to do it in a different way then please let me know.

Aha! Interesting. Now I understand :) I haven’t really noticed that you are retrieving comments one by one in your actionMod.

Some checks if you like:

[list=1]

[*]What’s the purpose of these lines for both ajax links? Are they not in conflict with ajax’s urls?


'href' => Yii::app()->createUrl('post/moderate'),

[*]Are you sure that your actionMod actually runs? Have you tried to [font="Courier New"]if($model != null) echo $model->id;[/font] just instead of the renderPartial?

[/list]

Otherwise, another approach would be to refresh only the ajax url in both your spans, since it’s the id that really changes (if there are still pending comments). But for that, afaik, I’d use jQuery to hook the ajax to my links not the ajaxLink helper.

As far as I know, CHtml::ajax* in a partial view will not work when it is renderPartial-ed as an ajax response.

(It should work for the 1st time, but will not in the 2nd and after.)

It may work when you set the 4th parameter of renderPartial to ‘true’, … I’m not sure.

I would rather do it differently. … maybe just like bennouna would do.

  1. send all the scripts to the client in the initial response

  2. use jquery.on() to attach an event handler to the ajax updated contents

  3. send no scripts in ajax responses, plain html only

Main view file … moderate.php




...

$url = $this->createUrl('post/mod');

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

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


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

$('#moderate-container').on('click', 'a.mod-yes, a.mod-no', function(event){

	var href = $(this).attr("href");

	// tricks to retrieve the parameters

	var post_id = href.match(/post_id=(\\d+)/)[1];

	var status = href.match(/status=(\\d+)/)[1];

	$.ajax({

		'type' : 'POST',

		'url' : '$url',

		'dataType' : 'html',

		'data' : {

			'post_id' : post_id,

			'status' : status,

			'$csrf_token_name' : '$csrf_token'

		},

		'success' : function(data){

			$('#moderate-container').html(data);

		}

	});

	event.preventDefault();

});

");

...



Partial view file … _mod.php




<p class="story-approval-btns center">

<span class="moderate-yes">

<?php echo CHtml::link('Yes',

	array('post/moderate', 'post_id'=>$model->id, 'status'=>Post::STATUS_APPROVED),

	array('class'=>'mod-yes'));

?>

</span>

<span class="moderate-no">

<?php echo CHtml::link('No', 

	array('post/moderate', 'post_id'=>$model->id, 'status'=>Post::STATUS_REJECTED),

	array('class'=>'mod-no'));

?>

</span>

</p>



[NOTE]

jquery.on() should be based on an element that will not be changed by ajax updates.

$(‘body’) should be the safest, but I think $(’#moderate-container’) is OK in this context.

Thanks to your both @softarc and @bennouna. I’ll give these options a try and let you know.

Problem was in controller where I was calling the find() function in actionMod() on controller instead on model. It worked fine once I changed




$this->find()



to


Post::model()->find()

Silly mistake wasted a lot of my time. There was another minor issue that params in the find call had


':status='=>

instead of


':status'=>

Thanks everyone for the help.