Multiple Models In One Form

Update:

Since below can be interpreted as ‘vague’, here my more concrete question:

Is it possible, and if so, what is the best way, to render a form partially after a selection of a dropdown list.

A user can select the number of tickets he/she wants to order and then that number of forms need to be rendered in a <div>.

In my opinion the question can be summarized to:

  • how to send a full model via Ajax to a Controller (to call the renderPartial)

(if possible)…

My only solution would be to render and hide all (ticket) forms, and show

these upon selection of the dropdown. However, this does not seem to be a

‘neat’ solution.

Thanks in advance!

========

Earlier description:

Hi there,

As ‘newbie’, I am struggling with the best way to implement the following case:

I am building a ticket system, where visitors can buy one or multiple personal ticket(s).

Therefore, I created a model ‘Bezoeker’ (Dutch for visitor) with the usual CRUD forms, including

the internal relation of ‘besteld_door’ (=‘ordered_by_user_id’). Each ‘ticket’ should contain at

least the attributes ‘name’, ‘age’, and ‘city’.

My primary question is in what way you would implement this.

How can I create a form where I retrieve the ‘order_by_user’ information AND where the visitor

can select a number and that number of forms is displayed to also retrieve multiple other formInfo.

Currently, I have found a work-a-round, but I am currious whether you would do the same and what

improvements can be made, as I am not convidence enough whether this is the best option.

I hope you would like to think with me.

=====

What I currently created:

I created an extra action in the BezoekerController called ‘order’, where the model Bezoeker is

initiated and the maximum number of ShortBezoeker (since some data of the buyer will be copied to

the ‘childs’ and therefore the form does not need to contain all the info. Furthermore I thought

it would be better to a slightly different model for the extra information, since it is used in one form.

Then the function in my BezoekerController is:


public function actionOrder(){

   $maxNum = 4;

   $model = new Bezoeker;

   $extraUsers = array();

   for($i = 0; $i < $maxNum; $i++){

      $extraUsers[$i] = new ShortBezoeker('insert');

   }		 

		

   $allModels = array_merge(array($model), $extraUsers);

   $this->performAjaxValidation($allModels);


   if(isset($_POST['Bezoeker'])){

        $num = $_POST['Bezoeker']['number'];

	if($num <= $maxNum){

	  $extraUsers = array_slice($extraUsers, 0, $num);		// only get the users which are filled


	   /* Set model attributes */	

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

	  $model->time_created	= date("Y-m-d H:i:s", time());

	  $model->generateAndSetBarcode();


	  foreach($extraUsers as $i => $userModel){

		$userModel->attributes	= $_POST['ShortBezoeker'][$i];

		$model->time_created	= date("Y-m-d H:i:s", time());

		$model->generateAndSetBarcode();

	  }


	  /* Validate models */

	  $valid = $model->validate();

	  foreach($extraUsers as $userModel){

		$valid = $userModel->validate() && valid;

		if(!$valid)

		   continue;

	  }


	  /* Save models */	

	  if($valid){

		$success = $model->save();


		$bestellerId = $model->id;

		foreach($extraUsers as $userModel){

			$userModel->besteld_door = $bestellerId;

			$success = ($userModel->save() && $success);

			if(!$success)

		   	   continue;

	        }


    	        if($success){

		   Yii::app()->user->setFlash('success', 'Your order have been places!');

  		   $this->redirect(array('//site/index'));

	        }				

	  }

        }

   }

		

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

			'model'			=> $model,

			'extraUsers'	=> $extraUsers,

			'maxAantalExtra'=> $maxNum,

			'indicaties'	=> Indicatie::model()->findAll(array('order'=>'beschrijving')),

			'status'	=> StatusBezoeker::model()->findAll(array('order'=>'beschrijving'))

		));



User create just renders user_form:




<?php $form=$this->beginWidget('bootstrap.widgets.TbActiveForm',array(

	'id'			=> 'bezoeker-form',

	'type'			=> 'horizontal',

	'htmlOptions'	=> array('enctype'=>'multipart/form-data'),


	'enableAjaxValidation' => true,

	'clientOptions'=>array(

		'validateOnChange'=>true,

		'validateOnSubmit'=>true,

	),

)); ?>


<p class="help-block">Fields with <span class="required">*</span> are required.</p>


<?php // echo $form->errorSummary(array_merge(array($model), $extraUsers)); ?>


<?php echo $form->dropDownListRow($model, 'aantal', 

			array_merge(array(0=>'---'), range(1, $maxAantalExtra)), 

			array('class'=>'span5',

			'onChange'=>"updateAantal($(this).val());")); ?>


<?php echo $form->textFieldRow($model,'voornaam',array('class'=>'span5','maxlength'=>35)); ?>

<?php echo $form->textFieldRow($model,'achternaam',array('class'=>'span5','maxlength'=>100)); ?>

<?php echo $form->textFieldRow($model,'mailadres',array('class'=>'span5','maxlength'=>255)); ?>

<?php echo $form->datepickerRow(

            $model,

            'geboortedatum',

            array(...),

        ); ?>

<?php echo $form->textFieldRow($model,'stad',array('class'=>'span5','maxlength'=>150)); ?>

<?php echo $form->dropDownListRow($model, 'indicatie_id',

			CHtml::listData($indicaties, 'id', 'beschrijving'),

				array(	'prompt'=>'',

					'class' => 'span5',

					'hint' => "..."));?>

<?php

	for($i = 0; $i < 1; $i++){

	   $this->renderPartial('//bezoeker/_extra_user_form', array('model'=>$extraUsers[$i], 'form'=>$form, 'i'=>$i));

	}

?>

<div class="form-actions">

	<?php $this->widget('bootstrap.widgets.TbButton', array(

			'buttonType'=>'submit',

			'type'=>'primary',

			'label'=>$model->isNewRecord ? 'Plaats bestelling' : 'Sla bestelling op',

		)); ?>

</div>

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



Here, I just started with a for-loop for one extra form, to first manage that, before working with AJAX etcetera. Later on, there will be a <div> with a certain ID i think and then on update of the dropbox name=‘aantal’, the selected number of forms will be partially rendered.

Then the extra_user_form is:


<?php echo $form->textFieldRow($model,'['. $i .']voornaam',array('class'=>'span5','maxlength'=>35)); ?>

<?php echo $form->textFieldRow($model,'['. $i .']achternaam',array('class'=>'span5','maxlength'=>100)); ?>

<?php echo $form->textFieldRow($model,'['. $i .']mailadres',array('class'=>'span5','maxlength'=>255)); ?>

<?php echo $form->datepickerRow(

            $model,

            '['. $i .']geboortedatum',

            array(...),

        ); ?>

<?php echo $form->textFieldRow($model,'['. $i .']stad',array('class'=>'span5','maxlength'=>150)); ?>

==

My current struggle is with: The Ajax validation of multiple forms, however I wanted to post this topic to learn from your experiences, when possible.

=====

Thanks in advance

and I hope you can provide me with some feedback, whether this is the correct way of handling this, or whether you would suggest some other possibilities.

Looking forward for your response!

With kind regards,

Reinier