Workaround For Cgridview In Cjuitabs Ajaxtab Resulting In Multiple Requests

I have a CGridView with delete button in a CjuiTabs ajaxTab.

I tried many techniques, such as


Yii::app()->clientScript->scriptMap['jquery.js'] = false;

Yii::app()->clientScript->scriptMap['jquery.min.js'] = false;

and


'options'=>array(

	'live'	=> false,

	'class'	=> uniqid(),

	'id'	=> uniqid(),

),

and

jquery event delegation,

and


render, renderPartial, renderPartial(..., false, true)

and some extensions, but I was not able to prevent the loading of multiple scripts (resulting in multiple requests/submissions). I sometimes got very close to having it working, but things normally turned ugly after pagination.

So, until I understand more about the inner-workings of script management, I am using the following - maybe weird - workaround, which involves an iframe in the Tab:

In the controller I have three actions:

actionUpdate renders form1.php, which contains the CJuiTabs.

actionAdmin2 renders the levels.php view that is displayed in the ‘Levels’ tab. actionAdmin2 uses a layout and normal render(). No renderPartial(). levels.php contains the CGridView.

actionDelete2 deletes the records from the CGridView, and then returns without rendering anything.

In form1.php I turned the ajaxTab into a normal tab with the iframe. When the view is rendered, the iframe’s ‘src’ calls actionAdmin2, which renders the CGridView.


$tabs = array();

		

$prms=array(

	'parentId' => $parentId

);


$iframeUrl = $this->createUrl('controller/admin2', $prms);


$tabs['Levels'] = array(

	'id'=>'Levels',

	'content'=>'

		<div class="row-fluid">

			<iframe id="iframe1_2" name="iframe1_2"

				width="80%" height="80%"

				src="'. $iframeUrl . '"></iframe>

		</div>

	',

);

			

			

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

	'id'		=> 'icTabs',

	'tabs' 		=> $tabs

));

levels.php has the following parameters (obviously you can pass them to this view from the controller):


$prms=array('parentId' => $parentId);

$iframeUrl = $this->createUrl('controller/admin2', $prms); 

$iframe = '#iframe1_2'; 

The CGridView in levels.php has the following delete button code:


'template'=>'{icdelete}',

						

'buttons'=>array(

	'icdelete'=>array(

		'label'=> 'Delete',

		'icon' => false,

		'imageUrl'=>Yii::app()->baseUrl.'/images/css/gridview/delete.png',

		'url'=>'$this->grid->controller->createUrl("delete2", array(

			"idValue"	=>	$data->primaryKey,

		))',

								

		'click'=>"function(){

			confirm_delete(

				$(this).attr('href'),

				'".$iframe."',

				'".$iframeUrl."'

			);

			return false;

		}",

	),

),

The code "in" the iframe (levels.php) must have access to the following js function:


function confirm_delete($url, $iframe, $iframeUrl)

{

	try{

		$messg = "Are you sure you want to DELETE this record?";		

		if(!confirm($messg)){

			return false;

		}


		var request = $.ajax({

		  url: $url,

		  type: "GET",

		  cache: false,

		  dataType: "html" 

		});

		

		request.done(function(response){

			/* reset iframe src */

			parent.setIframeInDialogSource($iframe, $iframeUrl);

			return false;

		});

		

		request.error(function(jqXHR, status, error){

			alert (error + ": " + jqXHR.responseText);

        });

	}

	catch(error){

		alert(error.message + '. ' + 'Please contact us.');

		return false;

	}

}

The code “under” the iframe (the iframe’s parent - such as form1.php) must have access to the following js function:


function setIframeInDialogSource($iframe, $iframeUrl)

{

	try{

		$($iframe).attr("src", $iframeUrl);

	}

	catch(error){

		alert(error.message + '. ' + 'Please contact us.');

		return false;

	}

}

Usage:

The delete button calls confirm_delete, which sends the request to actionDelete2.

actionDelete2 deletes the record and return without rendering anything (you can have the action return a success/fail response and have the confirm_delete function act accordingly).

confirm_delete then calls setIframeInDialogSource($iframe, $iframeUrl) in its parent. This function resets the iframe’s ‘src’, which results in a request to actionAdmin2 to reload the entire view.

Disadvantages:

One extra trip to the server.

Maybe loading a fraction slower - because render() loads all scripts and css with each request (but this can be fine tuned).

Advantages:

The iframe separates the scripts of widgets "in" the iframe, from widgets "under" the iframe. Thus, much smaller possibility of scripts overriding each other.

ALL widgets in the view and their associated js are refreshed - each time the view is rendered.

You can use render() with a layout. No struggling with renderPartial sometimes not loading "all" needed code for all the widgets in the view.

Much less worries about what js files to include and what to exclude.

Good for beginners like me ::)