[EXTENSION] multimodelform/jqrelcopy

Hi Joblo,

Thanks a lot. Sorry for not making clear on my second question. I am aware there is a option to add remove link in the rows which we clone. I am asking things in update mode. In update mode , i want to add a remove option in the rows which i reproduced. How to acheive that ?

Thanks, great mod!. I think this must be a core function, it would be great see it soon.

See ya.

Hi Joblo, I want to ask about earlier problem I sent you long time ago,

this is my form config


$detailFormConfig = array(

      'elements'=>array(

        'product_id'=>array(

            'type'=>'dropdownlist',

			'items'=>Product::model()->getProductOptions(),

			'prompt'=>'-- Select Product --',

			'onchange'=>'

				var text = $("select#InvoiceDetail_product_id option:selected").html();

				var last = text.lastIndexOf(" ");

				var price = text.substring(last,text.length);

				$("#InvoiceDetail_price").val(price);

			',

        ),

        'quantity'=>array(

            'type'=>'text',

        ),

        'price'=>array(

            'type'=>'text',

        ),

		'discount'=>array(

            'type'=>'text',

			'value'=>'0',

        ),

    ));

That works just for first detail row, and about cloning the form as well as the javascipt code I don’t really know how to do that with jsAfterClone etc. Name of the id is generated like copy1,copy2, and so on… how can I get the specific cloned id like price and discount field


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

		'tableView' => true,

        'id' => 'id_detail', //the unique widget id

        'formConfig' => $detailFormConfig, //the form configuration array

        'model' => $detail, //instance of the form model

		'jsAfterClone' => '

		alert(this.attr(\'class\'));

		// what/how to do in here? 

// I want to do like above code, set the price and discount value

		',

.....



thanks for the help

I would play around in the ‘jquery.relcopy.yii.1.0.js’ in the assets (alert(newid), val, substring…).

See the code at line 90, when cloning the children.

Here you have to assign the onchange to the cloned elements.

When it’s working, you can move the code to ‘jsAfterClone’ => ‘…’ (=funcAfterNewId)




	// Increment Clone Children IDs

	$(clone).find('[id]').each(function(){

		var newid = $(this).attr('id') + (counter +1);

		funcBeforeNewId.call($(this));

		$(this).attr('id', newid);

		funcAfterNewId.call($(this));


                ... your testcode here ....    

                    

	});




Hello Joblo,

I am getting an error "Array to String Conversion" on my multimodel form. This is the only form in my app that gives this error. I have another form that uses the same rules() and saves the information with no problem. Can you help me find the problem?

Here’s my controller:


 <?php


class memberController extends Controller

{

        /**

                * @var string the default layout for the views. Defaults to '//layouts/column2', meaning

                * using two-column layout. See 'protected/views/layouts/column2.php'.

                */

        public $layout='//layouts/column2';


        /**

                * @return array action filters

                */

        public function filters()

        {

                return array(

                        'accessControl', // perform access control for CRUD operations

                );

        }


        /**

                * Specifies the access control rules.

                * This method is used by the 'accessControl' filter.

                * @return array access control rules

                */

        public function accessRules()

        {

                return array(

                        array('allow',  // allow all users to perform 'index' and 'view' actions

                                'actions'=>array('index','view'),

                                'users'=>array('*'),

                                

                        ),

                        array('allow', // allow authenticated user to perform 'create' and 'update' actions

                                'actions'=>array('create','update','create2'),

                                'users'=>array('@'),

                        ),

                        array('allow', // allow admin user to perform 'admin' and 'delete' actions

                                'actions'=>array('admin','delete'),

                                'users'=>array('admin'),

                        ),

                        array('deny',  // deny all users

                                'users'=>array('*'),

                        ),

                );

        }


        /**

                * Displays a particular model.

                * @param integer $id the ID of the model to be displayed

                */

        public function actionView($id)

        {

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

                        'model'=>$this->loadModel($id),

                ));

        }


        /**

                * Creates a new model.

                * If creation is successful, the browser will be redirected to the 'view' page.

                */

        public function actionCreate()

        {

                $model=new member;


                // Uncomment the following line if AJAX validation is needed

                // $this->performAjaxValidation($model);


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

                {

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

                        if($model->save())

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

                }


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

                        'model'=>$model,

                ));

        }

        

        public function actionCreate2()

{

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

 

        $model = new member;

 

        $member = new member;

        $validatedMembers = array();  //ensure an empty array

 

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

        {

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

 

        if( //validate detail before saving the master

                MultiModelForm::validate($member,$validatedMembers,$deleteItems) &&

                $model->save()

        )

        {

                //the value for the foreign key 'groupid'

                $masterValues = array ('groupid'=>$model->id);

                if (MultiModelForm::save($member,$validatedMembers,$deleteMembers,$masterValues))

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

                }

        }

 

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

        'model'=>$model,

        //submit the member and validatedItems to the widget in the edit form

        'member'=>$member,

        'validatedMembers' => $validatedMembers,

        ));

}

        

        

  




        /**

                * Updates a particular model.

                * If update is successful, the browser will be redirected to the 'view' page.

                * @param integer $id the ID of the model to be updated

                */


                public function actionUpdate($id)

        {

                $model=$this->loadModel($id);


                // Uncomment the following line if AJAX validation is needed

                // $this->performAjaxValidation($model);


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

                {

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

                        if($model->save())

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

                }


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

                        'model'=>$model,

                ));

        }


        /**

                * Deletes a particular model.

                * If deletion is successful, the browser will be redirected to the 'admin' page.

                * @param integer $id the ID of the model to be deleted

                */

        public function actionDelete($id)

        {

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

                {

                        // we only allow deletion via POST request

                        $this->loadModel($id)->delete();


                        // if AJAX request (triggered by deletion via admin grid view), we should not redirect the browser

                        if(!isset($_GET['ajax']))

                                $this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('admin'));

                }

                else

                        throw new CHttpException(400,'Invalid request. Please do not repeat this request again.');

        }


        /**

                * Lists all models.

                */

public function actionIndex()

{

        $criteria = new CDbCriteria();


        if(isset($_GET['qs']))

        {

        $qs = $_GET['qs'];

        $criteria->compare('name', $qs, true, 'OR');

 

        }


        $dataProvider=new CActiveDataProvider("member", array('criteria'=>$criteria));


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

        'dataProvider'=>$dataProvider,

        'pagination'=>false,

        $dataProvider->pagination->pageSize=50000000,

        'name'=>'ajax',

        ));

}


        /**

                * Manages all models.

                */

        public function actionAdmin()

        {

                $model=new member('search');

                $model->unsetAttributes();  // clear any default values

                if(isset($_GET['member']))

                        $model->attributes=$_GET['member'];


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

                        'model'=>$model,

                ));

        }


        /**

                * Returns the data model based on the primary key given in the GET variable.

                * If the data model is not found, an HTTP exception will be raised.

                * @param integer the ID of the model to be loaded

                */

        public function loadModel($id)

        {

                $model=member::model()->findByPk($id);

                if($model===null)

                        throw new CHttpException(404,'The requested page does not exist.');

                return $model;

        }


        /**

                * Performs the AJAX validation.

                * @param CModel the model to be validated

                */

        protected function performAjaxValidation($model)

        {

                if(isset($_POST['ajax']) && $_POST['ajax']==='service-member-form')

                {

                        echo CActiveForm::validate($model);

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

                }

        }

}



And here is the form:


<div class="form wide">

 

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

    	'id'=>'bulk-form',

    	'enableAjaxValidation'=>true,

)); ?>

 

<p class="note">Fields with <span class="required">*</span> are required.</p>

 

<?php

 

// see http://www.yiiframework.com/doc/guide/1.1/en/form.table

// Note: Can be a route to a config file too,

//   	or create a method 'getMultiModelForm()' in the member model

 

$memberFormConfig = array(

  	'elements'=>array(

    	'name'=>array(

        	'type'=>'text',

			

        	'maxlength'=>40,

	),

	  

    	'rankLevel'=>array(

        	'type'=>'text',

			

        	'maxlength'=>40,

   	

    	),

		'Tag'=>array(

        	'type'=>'text',

			

        	'maxlength'=>40,

   	

    	),

		'dept'=>array(

        	'type'=>'text',

		

        	'maxlength'=>40,

   	

    	),

		'dateTag'=>array(

        	'type'=>'text',

			

        	'maxlength'=>40,

   	

    	),

		'date'=>array(

        	'type'=>'text',

		

        	'maxlength'=>40,

     	

    	),

		

	));

 

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

    	'id' => 'id_member', //the unique widget id

    	'formConfig' => $memberFormConfig, //the form configuration array

    	'model' => $servicemember, //instance of the form model

    	//if submitted not empty from the controller,

    	//the form will be rendered with validation errors

    	'validatedItems' => $validatedMembers,

 

    	//array of member instances loaded from db

    	'data' => $servicemember->findAll('branchId=:branchId', array(':branchId'=>$model->id)),

	));

?>

 

<div class="row">

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

		<?php echo $form->hiddenField($model,'ip3',array('value'=>Yii::app()->request->userHostAddress,)); ?>

		

		

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

		<?php echo $form->hiddenField($model,'branchId',array('value'=>1,)); ?>

	

	</div> 

 

<div class="row buttons">

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

</div>

 

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

 

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

Here’s the stack trace:


Array to string conversion

(D:\WAMP\www\yii-1.1.8.r3324\framework\db\CDbCommand.php:256)

Stack trace:

#0

D:\WAMP\www\yii-1.1.8.r3324\framework\db\schema\CDbCommandBuilder.php(98):

CDbCommandBuilder->bindValues()

#1 D:\WAMP\www\yii-1.1.8.r3324\framework\db\ar\CActiveRecord.php(1607):

CDbCommandBuilder->createFindCommand()

#2

D:\WAMP\www\yii-1.1.8.r3324\framework\validators\CUniqueValidator.php(97):

member->exists()

#3 D:\WAMP\www\yii-1.1.8.r3324\framework\validators\CValidator.php(192):

CUniqueValidator->validateAttribute()

#4 D:\WAMP\www\yii-1.1.8.r3324\framework\base\CModel.php(152):

CUniqueValidator->validate()

#5 D:\WAMP\www\yii-1.1.8.r3324\framework\db\ar\CActiveRecord.php(780):

member->validate()

#6

D:\WAMP\www\yii-1.1.8.r3324\APP\protected\controllers\memberController.php(97):

member->save()

#7 D:\WAMP\www\yii-1.1.8.r3324\framework\web\actions\CInlineAction.php(50):

memberController->actionCreate2()

#8 D:\WAMP\www\yii-1.1.8.r3324\framework\web\CController.php(300):

CInlineAction->runWithParams()

#9 D:\WAMP\www\yii-1.1.8.r3324\framework\web\filters\CFilterChain.php(134):

memberController->runAction()

#10 D:\WAMP\www\yii-1.1.8.r3324\framework\web\filters\CFilter.php(41):

CFilterChain->run()

#11 D:\WAMP\www\yii-1.1.8.r3324\framework\web\CController.php(1144):

CAccessControlFilter->filter()

#12

D:\WAMP\www\yii-1.1.8.r3324\framework\web\filters\CInlineFilter.php(59):

memberController->filterAccessControl()

#13

D:\WAMP\www\yii-1.1.8.r3324\framework\web\filters\CFilterChain.php(131):

CInlineFilter->filter()

#14 D:\WAMP\www\yii-1.1.8.r3324\framework\web\CController.php(283):

CFilterChain->run()

#15 D:\WAMP\www\yii-1.1.8.r3324\framework\web\CController.php(257):

memberController->runActionWithFilters()

#16 D:\WAMP\www\yii-1.1.8.r3324\framework\web\CWebApplication.php(277):

memberController->run()

#17 D:\WAMP\www\yii-1.1.8.r3324\framework\web\CWebApplication.php(136):

CWebApplication->runController()

#18 D:\WAMP\www\yii-1.1.8.r3324\framework\base\CApplication.php(158):

CWebApplication->processRequest()

#19 D:\WAMP\www\yii-1.1.8.r3324\APP\index.php(25): CWebApplication->run()

REQUEST_URI=/yii-1.1.8.r3324/APP/index.php/member/create2

I really hope I can get this fixed as I need tabular input.

As you can probably see in the controller, I copied your sample code from the readme and simply added my model names, etc.

Seems to be not a multimodelform issue.

See line 97: $model->save()




D:\WAMP\www\yii-1.1.8.r3324\APP\protected\controllers\memberController.php(97):

member->save()



There is a problem on validating the $model - see the stack trace: ‘member->exists()’ (CUniqueValidator).

You should do a var_dump to take a look at the properties of the $model variable.





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

        {

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

        var_dump($model); die();

        ..... 




If you can’t answer this question (I know it’s my code and my fault if there is something wrong) can you atleast tell me how to pull the “member” table into the main view? (group/index only displays the Group database. How can this be both Group and Member??)

You tell in the instructions to change the actionUpdate and actionCreate, but nothing about actionView or actionIndex.

EDIT: To make it clearer (and not trying to sound mean or demanding) what is the point of adding multiple entries if I cannot index them. How can I do so? :)

Take a look at the Blog tutorial and the code from the blog demo.

It’s the same as you would display ‘posts’ and ‘comments’.

Ok will do. Thanks.

It`s will be good - to make similar extension but without jqrelcopy - only for saving multimodelform

I don’t think this is necessary, because implementing this is not so much work and can be very special for each case.

See:

Tabular Input

How to use a single form to collect data for two or more models?

Hi,

Superb extension. I tried Group-Member example and it works fine for CREATE, UPDATE. How to i get it work for DELETE operation? Right now when i delete it removes only the Group record and not the related Member records.

Thanks

Deleting members should be done directly in the database.

Set the definition of the foreign keys: OnDelete -> cascade

Hi Joblo,

Thanks for your quick response. I tried your solution but still not working.

CREATE TABLE IF NOT EXISTS member (

id int(11) NOT NULL AUTO_INCREMENT,

groupid int(11) NOT NULL,

firstname varchar(100) NOT NULL,

lastname varchar(100) NOT NULL,

membersince int(11) NOT NULL,

PRIMARY KEY (id),

FOREIGN KEY (groupid) REFERENCES group(id) ON DELETE CASCADE

);

What database do you use?

Maybe sqlite doesn’t support this?

It should not be the job of the php-client to delete all members if a group is deleted.

But you can implement the onBeforeDelete/onAfterDelete event of the group model to delete the related members.

Thanks Joblo. I am using MySql. I will try it.

One more query:

How do i change the layout of the member elements, in _form, from vertical to horizontal? i.e.firstname, lastname, membersince are shown in vertical. I want them all in one row(horizontally).

Set the widget property ‘tableView’ to true.




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

       ...

       'tableView' => true,

       ...    

    ));




I added ‘tableView’ => true, and i got it the way i want but i also get the unwanted field groupid in the header. How to get rid of it?

Also in update, i get a new formconfig elements without clicking on Add Item. How to resolve this too?

I have gone through your whole post, but could not fix the issues mentioned above. Please help me.

Thanks

I thought this issue is fixed, but seems not.

Try to change the code in line 831 of MultiModelForm.php to:




   foreach($this->getElements() as $element)

	if ($element->visible && $element->type != 'hidden')

        {

   ....



Maybe $element->visible is not enough.

Clicking on ‘AddItem’ can only work, if there is an empty row added at the bottom of the other items.

So on updating I have to always add an empty item too, otherwise a user cannot add a new item in update mode.

But the empty row will not be saved.

Thanks the first issue is resolved :)

If i try adding new item and save it throws an Integrity constraint violation error.