Mini tutorial - CGridView / CRUD / CJuiDialog

Ciao a tutti, ho deciso di raccontarvi la mia prima esperienza con questo MVC ed un tentativo (abbastanza) riuscito di gestire le operazioni di CRUD dalla CGridView tramite un CJuiDialog.

La mia tecnica parte dalla generazione del codice con GII e sembra lasciare intatta la validazione ajax delle form ed è abbastanza semplice da implementare. Ho cercato di rendere, dove possibile, il codice generico.

Attendo vostri commenti. Sarei felice se collabboraste al perfezionamento di questo codice al fine di trasformare questo mini tutorial in una pagina del wiki.

Bruno

Let’s go. Dopo aver generato il codice con GII, assumo che il modello si chiami MyModel


Nel controller MyModelController:


Esempio di azione per la creazione di un nuovo elemento da modello:




	public function actionCreate()

	{

		$model=new MyModel;


		$this->performAjaxValidation($model);

		if(isset($_POST['MyModel']))

		{

			$model->attributes=$_POST['AdsList'];

			$result = $model->save();

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

            {

            	echo $result ? "ok" : "ko";

            	exit();

            }

            else 

            {

				$this->redirect(array('view','id'=>$model->id));					

			}

			 

				

		} 

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

        {

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

        } 

        else 

        {

			$this->render('create',array('model'=>$model));

		}

	}




Vista _create_dialog da creare all’interno della cartella delle viste

relative al modello in oggetto (es. views/MyModel/_create_dialog.php)


Esempio di azione per la creazione di un nuovo elemento da modello:




<?php

// Questa riga la devo a psikocrisis!!!

Yii::app()->clientScript->scriptMap=array(

         //scripts that you don't need inside this view

        'jquery.js'=>false,       

);

$this->beginWidget('zii.widgets.jui.CJuiDialog',array(

                'id'=>'createDialog',

                'options'=>array(

                    'title'=>Yii::t('app','Create New Record'),

                    'autoOpen'=>true,  // naturalmente apriamo il dialog dopo il rendering

                    'modal'=>'true',  // finestra di modifica modale

                    'width'=>'640', // qui possiamo scegliere le dimensioni che ci gustano

                    'height'=>'500', // qui possiamo scegliere le dimensioni che ci gustano

                    'buttons'=>array(

                    	Yii::t('app','Save')=>'js:function() { submitForm(this) }',

                    	Yii::t('app','Close')=>'js:function() { $(this).dialog("close"); }'

                    	), // Notare i bottoni di SAVE e CLOSE <img src='http://www.yiiframework.com/forum/public/style_emoticons/default/smile.gif' class='bbc_emoticon' alt=':)' />:)<img src='http://www.yiiframework.com/forum/public/style_emoticons/default/smile.gif' class='bbc_emoticon' alt=':)' />

                    'close'=>'js:function() {  $(this).html(""); updateGrid() }' // sul salva aggiorna la grid

                ),

                

                ));


// questo renderizza la nostra classica form <img src='http://www.yiiframework.com/forum/public/style_emoticons/default/smile.gif' class='bbc_emoticon' alt=':)' />

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


$this->endWidget('zii.widgets.jui.CJuiDialog');


?>




Nel file della vista principale, dove viene renderizzata normalmente la

CGridView, ossia admin.php, abbiamo una serie di accorgimenti semplicissimi:


A ) Dove viene registrato il javascript della ricerca:




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

$('#refresh-button').click(function(){

	$.fn.yiiGridView.update('ads-list-grid');

});

");



[u] B ) A fianco del link che apre la ricerca avanzata metto un altro link per il

refresh della grid che richiama lo script al punto A)[/u]




<?php echo CHtml::link(Yii::t('app','Refresh'),'#',array('id'=>'refresh-button')); ?>&nbsp;



C ) Subito dopo questo link, ne aggiungo un altro per la creazione di un record:




<?php 

	echo CHtml::ajaxLink(Yii::t('app','Add New'),

		Yii::app()->createUrl("MyModel/create"),

		array(

			'type'=>'POST',

			'url'=>'js:$(this).attr("href")',

			'update'=>'#updatediv', // il target della chiamata ajax è un div che mettiamo a fine pagina

			'cache'=>'false'

		),		

		array('id'=>'new-button')); 

?>



D ) Modifica alla riga di codice predefinita che crea la CGridView:




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



questa modifica serve per poter avere in $grid il widget e poter utilizzare del

codice generico nelle fasi successive:

[u] E ) A fine pagina, inserire il seguente codice che serve per forzare l’update della

grid e per inserire nella pagina il DIV target delle chiamate per la creazione del

dialog:[/u]




<?php 

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

function updateGrid() {

	$.fn.yiiGridView.update("' . $grid->id . '");

}',CClientScript::POS_END);

?>

<div id="updatediv"></div>	




Modifiche al file della vista _form presente in views/MyModel/_form.php


A ) In testa alla form:




<?php 


	$form=$this->beginWidget('CActiveForm', array(

	'id'=>'mymodel-list-form',

	'enableAjaxValidation' => true,	

	'clientOptions'=>array(

      'validateOnSubmit'=>false,

      'validateOnChange'=>true,

   ),

));


// Script per gestire l'invio dei dati della form al controller in modalità

// ajax ed eventualmente chiudere il form dopo il salvataggio o mostrare gli 

// errori di validazione.

Yii::app()->clientScript->registerScript($form->id . "-submit",'

function submitForm(dlg) {' .

	CHtml::ajax(array(

					'type'=>'POST',

					'cache'=>'false',

					'data'=>'js:$("form#'. $form->id . '").serialize()',

					'url'=>Yii::app()->request->requestUri,

					'success'=>'js:function(data) { if (data=="ok") { $(dlg).dialog("close"); return false; } else { alert("Error: " + data);} }'

                    )

				).'

}');



B ) Eliminare la row con i bottoni di salvataggio generati da GII

Per gestire la modifica, la tecnica è uguale. Basta modificare - in modo simile alla create - l’azione di update ed implementare le relative viste in modo affine a quanto visto sopra.

Magari è utile modificare il bottone della modifica nella CGridView, modificando il codice di default con questo snippet:




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

	'id'=>'mymodel-list-grid',

	'dataProvider'=>$model->search(),

	'filter'=>$model,

	'columns'=>array(

[...]

	),

	array

	(

		'class'=>'CButtonColumn',

		'template' => '{update} {delete}',

		'buttons'=>array(

			'update'=>array (

				'url'=> 'Yii::app()->createUrl("myModel/update", array("id" => $data->id))',

				'options'=>array (

					'ajax'=>array(

						'type'=>'POST',

						'url'=>'js:$(this).attr("href")',

						'update'=>'#updatediv',

						'cache'=>'false'

					),

				),

			),

		),

	),

);



Questo è quanto. Attendo speranzoso vostre idee / suggerimenti…

Grazie del post.

Volevo proprio provare ad implementare qualche cosa del genere. Farò delle prove e ti darò un riscontro.

Dai una occhiata a questa wiki.

In particolare c’e’ un suggerimento suggerimento di cui puoi fare tesoro:

  1. usa



 $('#dialogClassroom div.divForForm form').submit(someFunction);



In sostanza, dopo l’update assegna una funzione al submit della form in questa maniera, altri sistemi non funzionano con Opera.

Ciao Zac,

in realtà sono andato un pò oltre, anche se non ho aggiornato questo topic :) In effetti mi sono accorto che il mio codice non consentiva la validazione della form, cosa che può essere gestita sostituendo il codice della submitForm con quest’altro:




Yii::app()->clientScript->registerScript($form->id . "-submit",'

function submitForm(dlg) {

	' .

	CHtml::ajax(array(

		'type'=>'POST',

		'cache'=>'false',

		'dataType'=>'json',

		'data'=>'js:$("form#'. $form->id . '").serialize()+"&ajax='. $form->id . '"',

		'url'=>Yii::app()->request->requestUri,

		'success'=>'js:function(data) { 

			if (data!="") {

				if (data != null && typeof data == "object"){

					$.each(data, function(key, value) {

						$("#" + key).addClass("error");

						$("#" + key + "_em_").html(value[0]);

						$("#" + key + "_em_").show();

			        	});

				}

			} else {

				$.post("' . Yii::app()->request->requestUri . '",  $("form#'. $form->id . '").serialize(),

					function(res) {

						if (res.result=="ok") {

							$(dlg).dialog("close"); return false;

						}

					},"json");

			}

		}',

		'error'=>'js:function(jqXHR, textStatus,errorThrown) {  

				secondaryDialog("' . Yii::t('app','Application Error') . '", jqXHR.responseText); 

			}',

        )

	).'

}');

?>



In pratica la funzione di submit prova prima la validazione. Nel caso in cui la validazione non restituisce errori, viene fatta una POST. La post restituisce un oggetto json. Se il risultato è OK la finestra di dialogo viene chiusa. In alternativa si può eseguire il codice che si ritiene più opportuno.

Le azioni del controller vanno poi riviste in quanto devono restituire un oggetto JSON:




public function actionCreate() {

// ...

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

		$res = new stdClass();

		$res->result = ($result ? "ok" : "ko");

		echo json_encode($res);

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

	}

// ...

}



Ci sono anche altri punti che devo migliorare e riportare sul forum… spero di riuscirlo a fare quanto prima!!

Dai una occhiata alla wiki: stai seguendo lo stesso percorso che ho fatto io, credo che risparmierai un sacco di tempo con una breve lettura.