[EXTENSION] multimodelform/jqrelcopy

Hi again,

I’m once more stuck in a corner…

I’m using MMF and no problem but now I need to have a form with a file upload field.

First of all, if I understand correctly, MMF does not support these fields.

So I’ve downloaded the patch posted by dinhtrung (page 1 of this thread). I’ve also downloaded the example he posted but I couldn’t find any sign of MMF being used… doh!

My main model uses a function to init the form to be cloned, such as:


	public function getMMFDocConfig()

	{

		return array(

			'elements'=>array(

				'booking_id'=>array(

					'type'=>'hidden',

				),

				...

				'document_filename'=>array(

					'type'=>'file',

				),

			)

		);

	}



And in my view MMF works fine, with add/remove links and everything, for all child MMF’s.

In my controller I thus save this MMF the same way I do for the others child MMF.


			if (... &&

			 MultiModelForm::save($bookingdoc,$validatedBookingdocs,$deleteBookingdocs,$bookingValues) &&

			 $model->save()) {

                        ...



Problems are:

  • it seems I never get to execute this line in my controller when I save main model, turning off Ajax validation doesn’t change anything (a var_dump call placed right before MMF::save is never executed)

  • I’m then sent back to the edit form (not saved) and the file upload field shows error “filename can’t be blank”

  • I’ve also tried to manually add code to check for any CUploadedFile object, then I’ve checked MMF code and that should be done in there (by function initItems); with or without my code, nothing changes

Anybody has experience with these? Anyone could give hints or suggestions…?

TIA,

rash*

EDIT: meanwhile I’ve also tried another fork of MMF (by wandoledzep, that uses an older version of jquery relcopy) without success. It looks like I’m unable to find an example of using MMF with a file upload field…

Hi I have an issue and will be glad if someone can help me. Im using two dependable dropdownlist on the member form, the first dropdown use ajax to call a function that execute a query and sends the result to the other dropdown. The thing is that it works fine on the first item of create, but if I add another item it just don’t do it. After analize it we realize that multimodel add a number after the name of the item lets say that the first dropdown name is [modelname]_id_wbs, if I clone another item the name of the dropdown pass to be [modelname]_id_wbs2, so the function make reference to id_wbs it will never be able to update the other cloned items. Also doesn’t work on update section because multimodel add another thing to difference the saved items to the new ones. Keeping with the id_wbs example, the saved items will be [modelname]_u__0_id_wbs, [modelname]_u__1_id_wbs, and the new ones will be like the other example. If anyone has run with an issue like this can help me or tell me how did you solve it. Thanks.

This is the code of the dropdowns:


'id_wbs'=>array(

			            'type'=>'dropdownlist',

			            'style'=>'width:230px;',

			        	'items'=>CHtml::listData(Wbs::model()->findAll(array('condition'=>'active=1')), 'id', 'Fullwbs'),

			        	'ajax'=>array(

			    			'type'=>'POST',

			    			'url'=>CController::createUrl('Obtienecsi'),

			    			'update'=>'#CostComm_id_csi_code',

			    			),

'id_csi_code'=>array(

			            'type'=>'dropdownlist',

			        	'prompt'=>'Select',

			        	 ),



This is the function that calls the first drop down


public function actionObtienecsi()

	{	

		$idwbs=$_POST['CostComm']['id_wbs'][0];

		

		$sql = Yii::app()->db->createCommand()

		->select('csi_codes.id,CONCAT(csi_codes.csi_code," - ",csi_codes.client_code," - ",csi_codes.unit," - ",csi_codes.descr) as csi')

		->from('csi_codes')

		->leftJoin('v_change_ord_and_det', 'csi_codes.id = v_change_ord_and_det.id_csi_code')

		->leftJoin('bill_of_qtys', 'csi_codes.id = bill_of_qtys.id_csi_code')

		->where('(csi_codes.active = 1 AND (bill_of_qtys.active=1 OR v_change_ord_and_det.active=1) AND (v_change_ord_and_det.id_wbs=:idwbs OR bill_of_qtys.id_wbs=:idwbs))', array(':idwbs'=>$idwbs))

		->group('csi_codes.id')

		->queryAll();

		

		

		$datos = CHtml::listData($sql, 'id', 'csi');

		


		echo CHtml::tag('option',array('value'=>''),'Select',true);

		foreach($datos as $csicode=>$code)

		{

	    	echo CHtml::tag('option',array('value'=>$csicode),CHtml::encode($code),true);

		}





	}

Anyone have any success with integration of Jquery Chosen plugin Chosen with MMF, would really like to get that working together, I have a slight idea that I should use it as a widget,I just thought someone may have done that before :D

I had a similar issue a while back, I had to use a custom js solution for that, here is the logic

  • Detect select that has been clicked on

  • Strip out the unsimilar part of the returned click element and replace with the element you want to affect

Code snip




//Will detect change in any select containing "input" as part of the id name

$('select:[id*=input]').change(function (event) {

	//Get element that was changed

	var first_dropdown = event.target.id;

        //Replace input_item will now be input_cost

	var second_dropdown = item_id.replace("_item", "_cost");

	

        //Now second drop down contains the id for the dependent dropdown

        //Other logic for changing the dropdown continues here	

});




Hope that makes sense

Hi, thanks for the reply. I’ve been trying this but I just can’t get it. Did you apply it on the controller or directly in the form? Hope you can help me, your answer seems to have the solution to my issue. Thanks! ^_^

Put it up in the view that is the form directly, you can always use


Yii::app()->clientScript->registerScript()

in the view directly or in one of the controller actions or even use the normal script tags inside the form view, though the best option would be the register script functionality that Yii provides

Ok, thanks for your help, I’m gonna post the way I solve it just in case that someone else have the same issue.

Let’s say that we have two dependable dropdown list on the memberForm, the name of the first one is id_csi_code and the second one id_wbs.


'id_wbs'=>array(

		      		'label'=>CHtml::label( Yii::t('app', 'Bid Item'),'',array(

	        		'onmouseover'=>'js:{$(this).popover("show");}',

	        		'style'=>'display:inline; float:none;',

	        		//'class'=>"icon-comment", 

	        		'data-content'=>Yii::t('app', 'The Bid Item to be assigned the commitment.'),

	        		)),

	      		    'type'=>'dropdownlist',

		            'style'=>'width:230px;',

		        	'items'=>CHtml::listData(Wbs::model()->findAll(array('condition'=>'active=1')), 'id', 'Fullwbs'),

		        	'prompt'=>'Select',

					'class'=>'combosWBS'

		        	),

		        'id_csi_code'=>array(

			            'type'=>'dropdownlist',

			        	'prompt'=>'Select',

			        	'label'=>CHtml::label( Yii::t('app', 'Pay Item'),'',array(

	        		'onmouseover'=>'js:{$(this).popover("show");}',

	        		'style'=>'display:inline; float:none;',

	        		//'class'=>"icon-comment", 

	        		'data-content'=>Yii::t('app', 'The Pay Item code, description and unit of measure.')

	        		)),

			       	),		

And we have a function on the controller




public function actionObtienecsi()

	{	

		$idwbs=$_POST['id_wbs'];

		

                

		$sql = Yii::app()->db->createCommand()

		->select('csi_codes.id,CONCAT(csi_codes.csi_code," - ",csi_codes.client_code," - ",csi_codes.unit," - ",csi_codes.descr) as csi')

		->from('csi_codes')

		->leftJoin('v_change_ord_and_det', 'csi_codes.id = v_change_ord_and_det.id_csi_code')

		->leftJoin('bill_of_qtys', 'csi_codes.id = bill_of_qtys.id_csi_code')

		->where('(csi_codes.active = 1 AND (bill_of_qtys.active=1 OR v_change_ord_and_det.active=1) AND (v_change_ord_and_det.id_wbs=:idwbs OR bill_of_qtys.id_wbs=:idwbs))', array(':idwbs'=>$idwbs))

		->group('csi_codes.id')

		->queryAll();

		

		

		$datos = CHtml::listData($sql, 'id', 'csi');

		

               

		echo CHtml::tag('option',array('value'=>''),'Select',true);

		foreach($datos as $csicode=>$code)

		{

	    	echo CHtml::tag('option',array('value'=>$csicode),CHtml::encode($code),true);

		}

	}



So, having those functions, we can make a new javascript function on the same form where we have the dropdowns




<script type="text/javascript">

	$(document).ready(function(){


		$(".parent-model").on("change",".combosWBS",function(){

			var $combo = $(this).parents("td").next().find("select");

			$combo.prop("disabled", true);

			$.post("<?php echo CController::createUrl('Obtienecsi');?>",{id_wbs:$(this).val()},function(ret){

					$combo.html(ret);

					$combo.prop("disabled", false);

				});

		});

	});

	</script>



And that’s all. If you have questions can ask and I’ll do the possible to help you.

Goodvibes! ^_^

Hi,

i’m trying to set an advice for the users in a multimodelform config:




$relStudentSemesterFormConfig = array(

...

   'remarque1'=>array(

      'type'=> 'text',

      'value'=> "Si l'étudiant n'a pas assisté à une présentation de l'autoformation mais a reçu les consignes correspondantes, cocher la case suivante:",

	'style'=>'color:white; background-color:LightSlateGray; font-size: small',

	'size'=>105,

   ),

   'ind_info_autoformation'=>array(

	'type'=>'dropdownlist',

	'items'=>array(0 => 'Non', 1 => 'Oui'),

   ), 

...



The first field (remarque1) is a non database text, just to introduce the second one.

That’s works fine when i’m accessing form after the row is created, but when the row doesn’t exists, the first field didn’t appear.

Does anyone try this kind of stuff?

Have you seen the option at the end of the code of multimodel




$this->widget('ext.multimodelform.MultiModelForm',array(

'hideCopyTemplate' => false,

 ));



if you have it false, change it to true and vice versa. That should help for the field that doesn’t appear ^_^ BV

Autocomplete element finally works.

Good news, everyone!

Yeah, I made it. :)

The problem was an incorrect element copying: you shoud copy "autocomplete" element without data and events. (more information about it in Jquery API, clone() function )

Now, if you want to use autocomplete elements in your form - your code shoud look like this:




    /**

     * Support for CJuiAutoComplete. 

     *

     * @contributor Smirnov Ilya php1602agregator(at)gmail.com

     * @param array $element

     * @return string

     */

    public static function afterNewIdAutoComplete($element)

    {

        $options = isset($element['options']) ? $element['options'] : array();

        if (isset($element['sourceUrl']))

            $options['source'] = CHtml::normalizeUrl($element['sourceUrl']);

        else

            $options['source'] = $element['source'];


        $jsOptions = CJavaScript::encode($options);


        return "if ( this.hasClass('ui-autocomplete-input') )

            {

                var mmfAutoCompleteParent = this.parent();

                // cloning autocomplete element (without data and events)

                var mmfAutoCompleteClone  = this.clone();

                

                // removing old autocomplete element

                mmfAutoCompleteParent.empty();

                // re-init autocomplete with default options

                mmfAutoCompleteClone.autocomplete({$jsOptions});

                

                // inserting new autocomplete

                mmfAutoCompleteParent.append(mmfAutoCompleteClone);

            }";

    }



Please update the extension.

Hello again.

I’m also added a combobox widget support. ( yiiframework.com/extension/combobox )

In my application I use a Toph’s fork of combobox: github.com/kanyuga/yii-combobox (because this fork supports key=>value separation).

But it shoud work with main branch too (not tested).

Combobox plugin needs a small bugfix to work with multimodelform ( see my comment here: yiiframework.com/extension/combobox#c12257 )

Here is the code:




    /**

     * Support for EJuiComboBox

     * 

     * @contributor Smirnov Ilya php1602agregator[at]gmail.com

     * @param array $element

     * @param bool  $allowText

     * @return string

     */

    public static function afterNewIdComboBox($element, $allowText=true)

    {

        $options = array();

        if ( $allowText )

        {

            $options['allowText'] = true;

        }

        

        $jsOptions = CJavaScript::encode($options);

        

        return "if ( this.attr('type') == 'text' && this.hasClass('ui-autocomplete-input') ) 

            {

                var mmfComboBoxParent   = this.parent();

                // cloning autocomplete and select elements (without data and events)

                var mmfComboBoxClone    = this.clone();

                var mmfComboSelectClone = this.prev().clone();

                

                // removing old combobox

                mmfComboBoxParent.empty();

                // adding new cloden elements ()

                mmfComboBoxParent.append(mmfComboSelectClone);

                mmfComboBoxParent.append(mmfComboBoxClone);

                

                // re-init autocomplete with default options

                mmfComboBoxClone.combobox({$jsOptions});

            }

            

            if ( this.attr('type') == 'button' )

            {// removing old combobox button

                this.remove();

            }";

    }



Hi again,

I am trying to populate the clonable fields, so that it kind of operates as an update operation, is there anyway to do this without actually saving the "child" model initially?

Thank you Arely, but it didn’t change anything.

For my problem of not displayed field, it works when i’m specifying ‘visible’=>true.

I just don’t understand why i don’t need to specify for other fields, but as it works…

multimodelform dont work with scenarios?

http://www.yiiframework.com/forum/index.php/topic/41473-multimodelform/

Is it possible tu use Ajax Validation in a form created with the Multimodelform extension?

I’m trying to do it calling:


$this->performAjaxValidation(array($a,$<img src='http://www.yiiframework.com/forum/public/style_emoticons/default/cool.gif' class='bbc_emoticon' alt='B)' />);

Thank you

@ traceshankar or @Joblo,

I have similar requirement, do you have any working sample or can you guide where I can change to achieve this?

About all the problems above:

Sorry, it’s impossible for me to check all the specific problems (ajax, …) because I don’t have the time to create examples for all that stuff.

It would be nice if you publish simple examples (base on the demo-code) here. Then I can debug the code and maybe can offer a solution if possible.

Hi Joblo, here is the code sample. it is like fetching the value of a textfield from database based on selected value of dropdow n. both elements are inside multimodel form. here is the code for my _form.php:

<?php

$memberFormConfig = array(

  'elements'=&gt;array(


  


 				  


			'item_id'=&gt;array(


			'type'=&gt;'dropdownlist',


			'maxlength'=&gt;40,


			'visible'=&gt; true,


			'onmouseover'=&gt;'js:{&#036;(this).popover(&quot;show&quot;);}',


			'items'=&gt;Item::model()-&gt;getItems(),


			'prompt'=&gt;'Please select',


			'class'=&gt;'combosWBS',





	   				


	   'ajax'=&gt;array(	'type' =&gt; 'POST',


	   					'dataType'=&gt;'json',


	 				'data' =&gt; array('selitemid'=&gt; 'js:this.value'),


	  					'url'=&gt;CController::createUrl('loadmultiple'),


					'success'=&gt;'function(data){


          						alert(data);


							&#036;(&quot;#Orderline_qty&quot;).val(data.listprice);


									}')


    	


		 ),


		'qty'=&gt;array(


				'type'=&gt;'text',


				'maxlength'=&gt;40,


				'onmouseover'=&gt;'js:{&#036;(this).popover(&quot;show&quot;);}',


				'visible'=&gt; true


			),


			'listPrice'=&gt;array(


				'type'=&gt;'text',


				'maxlength'=&gt;40,


				'value'=&gt;'',


				'visible'=&gt; true


			),


			'salePrice'=&gt;array(


				'type'=&gt;'text',


				'maxlength'=&gt;40,


				'value'=&gt;'',


				'visible'=&gt; true


			),


   


));





&#036;this-&gt;widget('ext.multimodelform.MultiModelForm',array(


    'id' =&gt; 'id_member', //the unique widget id


    'formConfig' =&gt; &#036;memberFormConfig, //the form configuration array


    'model' =&gt; &#036;orderline, //instance of the form model


	'tableView' =&gt; true,





    'validatedItems' =&gt; &#036;validatedMembers,





    //array of member instances loaded from db


    'data' =&gt; &#036;orderline-&gt;findAll('order_id=:orderId', array(':orderId'=&gt;&#036;model-&gt;id)),


	


));

?>

As for controller:

public function actionCreate()

{


	 Yii::import('ext.multimodelform.MultiModelForm');


	&#036;model = new Order();


	&#036;orderline = new OrderLine();


	


	&#036;validatedMembers = array();


	&#036;model-&gt;orderDate = date('Y-m-d');


	&#036;model-&gt;status_id = '8';


	&#036;model-&gt;created_at = date(&quot;Y-m-d H:i:s&quot;);


	&#036;model-&gt;created_by = Yii::app()-&gt;user-&gt;id;


	&#036;model-&gt;isDeleted = '0';


	


	//&#036;orderline-&gt;order_id = &#036;model-&gt;id;


//	&#036;orderline-&gt;order_id = 0;


	


	&#036;orderline-&gt;created_at = date(&quot;Y-m-d H:i:s&quot;);


	&#036;orderline-&gt;created_by = Yii::app()-&gt;user-&gt;id;


	


	if (isset(&#036;_POST['Order'])) {


		//&#036;model-&gt;setAttributes(&#036;_POST['Order']);


		&#036;model-&gt;attributes=&#036;_POST['Order'];


		&#036;model-&gt;save();


		&#036;orderid = Yii::app()-&gt;db-&gt;createCommand(&quot;select max(id) from `order`&quot;)-&gt;queryScalar();


		&#036;masterValues = array ('order_id'=&gt;&#036;orderid);


		if (MultiModelForm::save(&#036;orderline,&#036;validatedMembers,&#036;deleteMembers,&#036;masterValues))


		 {


			&#036;this-&gt;redirect(array('view', 'id' =&gt; &#036;model-&gt;id));


		}


	}





	&#036;this-&gt;render('create', array( 'model' =&gt; &#036;model, 'orderline'=&gt;&#036;orderline,


    'validatedMembers' =&gt; &#036;validatedMembers


));


}


public function actionLoadmultiple()


{


	&#036;id = &#036;_POST['selitemid'];





&#036;prices = Item::model()-&gt;find('id=:id and isDeleted is NULL',array(':id'=&gt;&#036;id));


&#036;listprice = &#036;prices-&gt;listPrice;





echo CJSON::encode(array( 'listprice'=&gt;&#036;listprice));       

}

this works fine for first element and for second the error is duplicate id.

I was wondering if you could help??

Sorry … I mean a full yii app.

I can’t debug this, because I have no models Order, OrderLine …

But seems that multimodelform can’t work with ajax, because of the clientside js-code on cloning.