Richiamare Una View Esterna

Salve ragazzi, sono nuovo del mondo yii e sto trovando un po di difficoltà nel fare una cosa che senza questo framework faccio agevolmente.

Vi spiego il caso d’uso:

Ho una tabella articolo che ha n campi con 3 chiavi esterne, ora vorrei dare la possibilità tramite una modale (utilizzo bootstrap) di creare una di queste chiavi esterne senza dover uscire dalla pagina con evidente perdita di dati inseriti precedentemente.

Ho approcciato in diversi modi:

  1. ho provato a fare

$this->renderPartial('/fornitore/_form',array('model'=>$modelFornitore)); 

ma nel momento in cui clicco sul tasto crea della modale succede di tutto e ricarica la pagina senza inserire nulla anche perchè credo che $this del form a sto punto sia il controller da cui ho richiamato il form.

  1. allora ho provato ad “instanziare” un nuovo controller della chiave esterna così da fare render del solo form e non dell’intero create direttamente dal metodo actionCreate ma ho ottenuto un risultato peggiore

  2. giungo alla soluzione che a questo punto credo sia la migliore:


$modelFornitore = new Fornitore;

$modelFornitore->isExternal = true;

$this->renderPartial('/fornitore/_form',array('model'=>$modelFornitore));

qui in poche parole setto una variabile del model così da non visualizzare il tasto submit del form che richiamo (quindi modifico nella view)


<?php if(!$model->isExternal){?>

	<div class="row buttons">

		<?php echo CHtml::submitButton($model->isNewRecord ? 'Create' : 'Save'); ?>

	</div>

	<?php } ?>

Oltre al fatto che ora dovrei gestire il tutto con ajax (non so da dove iniziare per fare il bind di una funzione sul tasto salva della modale) vorrei sapere se l’approccio finale è quello consigliato o mi sto complicando enormemente la vita.

Grazie per l’eventuale aiuto, e scusate se non sono stato del tutto chiaro!

Notte

ciao, sono nuovo anch’io nel mondo yii quindi prendi la mia risposta con le pinze.

Il giusto approccio potrebbe essere questo !?

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

Ricordandoti di far aprire la dialog al click e impedire il caricamento della pagina


 

 array('onclick'=>'$("#dialog").dialog("open"); return false;')



E’ una cosa comune lavorare con tabelle con chiavi esterne.

Si crea, con gii, un model per ciascuna tabella e si sistemano le relations tra una e l’altra, così gestisce tutto Yii.

Avrai una form dove modifichi il record della tabella, giusto? Quella con 3 chiavi esterne intendo.

Nella form solitamente si crea una dropdown e Yii aggancia l’id selezionato al relativo campo. Cioè una dropdown per ciascun id.

Quindi niente necessità di ben 3 modal.

Ma anche volendo usare delle modal, non si pone il problema delle view "esterne".

Crei una view per ciascuna modal.

Nella view contenitore crei un div segnaposto con un id specifico.

Via $.ajax() fai caricare una action che ne fa il render e sul .done() della chiamata ajax semplicemente fai tipo così:




$.ajax ({

   url: '. $this->createUrl('actionRenderMiaModal') .'

...

}).done(function(data) {

   $('#history').html(data);

   $('#history #modal-1').modal('show');

});



A quel punto con poche righe di js gestisci anche il salvataggio. Agganci un evento al click sul pusante della modal (usando come selettore il container e specificando nell’on “(‘click’,‘selettore modal’)” , in questo modo l’evento funziona live su un elemento html ancora non presente.

Sempre via jQuery gli fai leggere il valore selezionato, fai una chiamata ajax ad un’altra action se salva questo valore, e sul .done di questa fai nascondere la modal, o visualizzarne un’altra con l’errore, o modificarne il testo per mostrare il risultato.

La strada della form con 3 dropdown è più rapida e secondo me è la migliore, anche per l’utente, ma è solo una mia opinione personale

Grazie delle risposte ragazzi e scusate per il mio ritardo!

Ho paura non ci siamo totalmente capiti.

Sono d’accordissimo con la tua risposta @realtebo di gestire il tutto con delle dropdown, ed in effetti è ciò che faccio.

Il mio problema esce fuori quando voglio "Creare un record di una chiave esterna".


<div class="row">

		<?php echo $form->labelEx($model,'categoria_idcategoria'); ?>

		<?php //echo $form->textField($model,'categoria_idcategoria'); ?>

		<?php

			$category_list = CHTML::listData(Categoria::model()->findAll(),'idcategoria','nome_categoria');

			$option = array(

				'tabIndex' =>'0',

				'empty' => 'Nessuna Categoria',

			);

		?>

		<?php echo $form->dropDownList($model,'categoria_idcategoria',$category_list,$option); ?>

		<br>

		<button class="btn btn-primary btn-lg" data-toggle="modal" data-target="#categoriaModal">

		Nuova Categoria

		</button>

		<!-- Modal -->

		

		<?php echo $form->error($model,'categoria_idcategoria'); ?>

	</div>


	<div class="row">

		<?php echo $form->labelEx($model,'fornitore_idfornitore'); ?>

		<?php

			$category_list = CHTML::listData(Fornitore::model()->findAll(),'idfornitore','ragione_sociale');

			$option = array(

				'tabIndex' =>'0',

				'empty' => 'Nessun Fornitore',

			);

		?>

		<?php echo $form->dropDownList($model,'fornitore_idfornitore',$category_list,$option); ?>

		<br>

		<button class="btn btn-primary btn-lg" data-toggle="modal" data-target="#fornitoreModal">

		Nuovo Fornitore

		</button>

		

		<?php echo $form->error($model,'fornitore_idfornitore'); ?>

	</div>

	<div class="row">

		<?php echo $form->labelEx($model,'url_foto'); ?>

		<?php echo $form->textArea($model,'url_foto',array('rows'=>6, 'cols'=>50)); ?>

		<?php echo $form->error($model,'url_foto'); ?>

	</div>


	<div class="row buttons">

		<?php echo CHtml::submitButton($model->isNewRecord ? 'Create' : 'Save'); ?>

	</div>


<?php $this->endWidget(); ?>


</div><!-- form -->

<div class="modal fade" id="categoriaModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">

		  <div class="modal-dialog">

		    <div class="modal-content">

		      <div class="modal-header">

			<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>

			<h4 class="modal-title" id="myModalLabel">Nuova Categoria</h4>

		      </div>

		      <div class="modal-body">

			<?php

				$modelCategoria = new Categoria;

				$this->renderPartial('/categoria/_form',array('model'=>$modelCategoria));

			?>

		      </div>

		      <div class="modal-footer">

			<button type="button" class="btn btn-default" data-dismiss="modal">Chiudi</button>

			<button type="button" class="btn btn-primary">Salva</button>

		      </div>

		    </div>

		  </div>

		</div>

<!-- Modal -->

		<div class="modal fade" id="fornitoreModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">

		  <div class="modal-dialog">

		    <div class="modal-content">

		      <div class="modal-header">

			<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>

			<h4 class="modal-title" id="myModalLabel">Nuovo Fornitore</h4>

		      </div>

		      <div class="modal-body">

			<?php

				$modelFornitore = new Fornitore;

				$modelFornitore->isExternal = true;

				$this->renderPartial('/fornitore/_form',array('model'=>$modelFornitore));

			?>

		      </div>

		      <div class="modal-footer">

			<button type="button" class="btn btn-default" data-dismiss="modal">Chiudi</button>

			<button type="button" class="btn btn-primary">Salva</button>

		      </div>

		    </div>

		  </div>

		</div>

Questa è la parte sia di form dove creo le dropdown sia dove creo il tasto per creare "nuovo record per la chiave esterna".

Estendo l’esempio dicendo che ho nel mio caso una tabella articolo che ha come chiavi esterne categoria e fornitore il mio intento è quello di dare la possibilità a chi inserisce un prodotto di creare anche una categoria oppure un fornitore “al volo” .

Con il renderPartial mi funziona la parte di visualizzazione della form nella modal, il mio problema è che però non posso usufruire delle validazioni e dei metodi che sono all’interno dei rispettivi controller .

Credo sia un problema comune. Avrei anche una mezza idea di come poter proseguire però mi domandavo quale fosse la "Best Practice".

Saluti ragazzi :D e grazie mille sempre dell’attenzione

Ora è più chiaro…

A questo punto io tenterei questa strada.

Dentro la create.php e dentro la update.php (che usano entrambe la _form.php) ci metteri il codice js e un div segnaposto per ospitare il contenuto della modal.

NB: per scrivere una sola volta il js, dentro create.php e update.php usare renderPartial("script"), per esempio…

Quando l’utente deve creare una nuova categoria, clicca sul pulsante, questo via js provoca il caricamento dell’html tramite actionCreate del fornitoreController.

cioè usa come url per l’ajax




$this->createUrl ("/fornitore/create");



A questo punto però devi provare a vedere cosa fa yii quando salvi da dentro la modal. Forse devi forzare l’uso dell’actionCreate del controller giusto.

Inoltre… quando tutto funzionerà, devi far si che alla chiusura della modal si aggiorni la dropdown perchè l’utente veda il nuovo fornitore o la nuova categoria … ma questo è un’altra storia

Mi ci si sono avvicinato?

Ottimo @realtebo hai colto in pieno il problema. Questa soluzione mi sembra ottima.

E forse ho anche capito dove sbagliavo.

Con ogni probabilità quello che ti dirò adesso sarà a tratti incomprensibile ma ci provo lo stesso!

Nel mio ragionamento, che non so quanto sia fattibile, volevo creare al click del tasto “Nuovo Fornitore” un nuovo FornitoreController in modo da gestire con l’actionCreate il tutto. Il problema era che con actionCreate lui renderizza poi tutta la pagina mentre a me serve solo la parte della form.

Quindi avevo deciso di inserire una variabile isExternal booleana all’interno del controller che settavo a true in questi casi di creazione di chiavi esterne.

Dunque nell’action create facevo un if che mi avrebbe mostrato solo il form anzichè tutto il create.

Putroppo non funzionava e ho intrapreso questa strada.

Volevo sapere se il ragionamento poteva essere corretto o meno(se ti è stato chiaro :D)

mi è abbastanza chiaro cosa hai cercato di fare, ma no, non è yii-compatibile … o almeno non è la strada migliore…

ci sono altre alternative ancora:

  • potresti seguire la strada di far manipolare alla stessa form due model diversi (ci sono alcune guide nella wiki), ma te lo sconsiglio, perchè poi auguri a spiegarlo agli utenti…

  • potresti far diventare stateFull la form e quando l’utente vuole creare un’altro fornitore passi ad un’altra pagina, lo crei e, magari ricavandoli dai cookie, dopo la sua creazione sai che devi tornare alla form, dove a questo punto potresti far selezionare in automatico il nuovo fornitore, e ricompilare quanto precedentemente compilato. Questa strada è pratica e ragionevole per l’utente finale. Personalmente, però, non ho mai lavoro in stateFull, per cui non ti saprei dare molto aiuto…

… e benvenuto sul forum ! non ti ho neppure accolto, che vergogna

Tranquillo, la migliore accoglienza è stata il tuo aiuto ;)

In effetti le altre due soluzioni le scarto per ora e mi tengo la prima da te postata, vedo un po come fare e nel caso riferisco come ho risolto :D

quando sarà il momento di dire ‘ho risolto’, si accettano dei + molto volentieri, anche per aiutare chi passa di qui a capire quali risposte del thread sono utili e quali, invece, erano solo chiacchiere

Va benissimo :D

Adesso sto avendo dei problemi con ajax, in verità non ho proprio capito il meccanismo.

Sto utilizzando un tema molto carino che si chiama abound, e utilizza bootstrap.

Infatti la parte del modal funziona in automatico, devo solo andare a toccare il content della modal inserendo la form inerente al tasto cliccato.




<?php

			// the link that may open the dialog

			$modal_button = '<button class="btn btn-primary btn-lg" data-toggle="modal" data-target="#Modal">Nuova Categoria</button>';

			$modelCategory = new Categoria;

			echo CHtml::link($modal_button, '#', array(

			   'onclick'=>'$("#Modal .modal-body").html("'.$this->renderPartial("/categoria/_form",array('model',$modelCategory)).'");return false;',

			));

		?>	



Ma mi da errore dicendo che non trova la variabile model… ma io la sto passando nell’array no?

Altra cosa fondamentale è come posso fare per richiamare ‘onclick’=>funzione dichiarata da me in un altro file…

Devi verificare DOVE ESATTAMENTE ti dice che non hai la variabile

Per favore, usa registerScript in cima alla view invece di usare js embedded nei tag, è illeggibile così il codice…

e poi tra ’ e " aperte e chiuse, è un attimo che ti impalli te e fai impallare Yii…

Metti in ordine e riprova. Metti un id al pulsante, quindi fai un registerScript con posizione onReady che tramite jQuery fa un




$('#tuopulsante').on('click',function() {

  $.ajax({

    url : '" . $this->createUrl ... . '" ,

  })

}



Così come l’hai scritta tu, non è un caricamento ajax… stai semplicemente mettendo TANTISSIMO html PRECARICATO dentro ad un elemento quando lo clicchi.

A questo punto ti fai un div segnaposto.

Dentro fai DIRETTAMENTE il renderPartial della modal. Usando il renderPartial come l’hai usato tu, che (in quel caso) va bene.

Sull on click fai semplicemente apparire la modal

Sul save da dentro la modal dovrai far si che il form vada alla action del controller giusto… ma questo ci arriviamo per ultimo, mi sa.

Provo a farti uno step by step

Diciamo che devi creare un articolo e dentro la form dell’articolo ‘al volo’ un fornitore…

ArticoloController

Qui ha l’actionCreate.

Dentro l’actionCreate ha il render della view “create”

Ed è a questo punto che DEVI passare ‘model’ => $model , dove $model = new Articolo e forse c’è già fatto qualche riga piu sopra

Vista create.php del controller Articolo

Qui hai un renderPartial che usa la vista “_form”. Anche in questo caso devi passare ‘model’ => $model

Qui devi usare registerScript … POS_READY per registrare l’evento ‘on click’ sul pulsante ‘Crea al volo un nuovo fornitore’.

Lo scopo dello script è solo fare




$('#id_del_container_della_modal').modal("show");



Perchè questo funzioni deve avere un elemento con un id ben noto che ti fa da container alla form.

Tipo




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



Sempre dentro a create.php avrai un DIV, e dentro a questo div fai il renderPartial della "_form" del controller Fornitore

Vista form.php

Dopo … bla bla bla …

avrai il tuo pulsante.

La magia… difficile

Sempre dentro allo script che avrai messo in create.php, devi aggiungere qualche altra riga di js per far si che quando il form fa il submit, venga mandato alla actionCreate del controller Fornitore e NON a quello del controller Articolo, e che il tutto avvenga via AJAX, perchè sennò ti cambia pagina.

Per farlo usa jQuery, sempre wrappato dentro un registerScript … POS_READY




$('selettore_tasto_save_della_modal').off('click'); 

$('selettore_tasto_save_della_modal').on('click', function(){

   $.ajax({

       url : '" . $this->createUrl('/fornitore/actionCreate') . "',

       type: "POST",

       data : ... qui devi passare una alla volta i valori della form

   }).done(function(data) {

       ... data è l'output di actionCreate di FornitoreController ... 

       ... per cui gli dovrai passare un parametro in piu per dirgli che sei via ajax e ti deve solo

       .,,, mandare giu, che so, l'id e il nome del fornitore appena creato ...


      .... quindi usi quell'id e il nome come opzione selezionata della combo dei fornitori

   })


  ;

}); 



… e sia chiaro che sto scrivendo di getto, ma la tecnica sta in piedi almeno in teoria.

… se diventa troppo difficile da capire (non lo è di certo da fare), pensa alla possibilità di aprire semplicemente una popup dove far creare il fornitore…