Yii 1.1: multimodelform

Handling of multiple records and models in a form
90 followers

This extension allows to work with multiple records and different models in a edit form. It handles clientside cloning and removing input elements/fieldsets and serverside batchInsert/Update/Delete.

Creating forms with this functionality is a 'tricky' workaround in views and controllers. This widget should do the main part of the work for you. It can be useful for order/registration forms ...

Find the latest releases on github

Features

  • Clientside Clone/Remove form elements / fieldsets with the jQuery plugin http://www.andresvidal.com/labs/relcopy.html
  • Simple handling of the submitted form data in the controllers create/update action
  • Simultanous editing multiple records and models (master/detail...)
  • Supports validation and error summary for each model/record
  • Autogenerating input form elements with the 'form builder' functionality of Yii
  • tableView (= gridView)
  • filefields with full upload handling and image preview in the edit form.

Notes

Not every form input element is supported.

You can use the most basic CFormInputElements (text, textarea, dropdownlist, ...).

Some input widgets need a workaround with js-code after clientside cloning. Currently supported with ready to use javascript code in methods:

  • CJuiDatePicker
  • datetimepicker
  • EJuiComboBox and CJuiAutoComplete (added by Smirnov Ilya)

Special handling:

  • Checkbox: you have to use a checkboxlist instead (see below and the demo.3.2)

New in v6.0.0

  • Filefield with fully handling all uploading and validating stuff

are not supported.

Requirements

  • Yii 1.1.6+

Usage

  • Extract the files under .../protected/extensions or use the composer

Master/Detail example:

You can find the implemtation explained below in the demo application.

Assume you have two models 'group' (id, title) and 'member' (id, groupid, firstname,lastname,membersince). The id attribute is the autoincrement primary key.

  • Generate the models 'Group' and 'Member' with gii. For testing the error summary set the members firstname/lastname as required in the rules.

  • Generate the 'GroupController' and the group/views with gii. You don't need to create a 'MemberController' and the member views for this example.

  • Change the default actionUpdate of the GroupController to

public function actionUpdate($id)
    {
        Yii::import('ext.multimodelform.MultiModelForm');
 
        $model=$this->loadModel($id); //the Group model
 
        $member = new Member;
        $validatedMembers = array(); //ensure an empty array
 
        if(isset($_POST['Group']))
        {
            $model->attributes=$_POST['Group'];
 
            //the value for the foreign key 'groupid'
            $masterValues = array ('groupid'=>$model->id);
 
            if( //Save the master model after saving valid members
                MultiModelForm::save($member,$validatedMembers,$deleteMembers,$masterValues) &&
                $model->save()
               )
                    $this->redirect(array('view','id'=>$model->id));
        }
 
        $this->render('update',array(
            'model'=>$model,
            //submit the member and validatedItems to the widget in the edit form
            'member'=>$member,
            'validatedMembers' => $validatedMembers,
        ));
    }
  • Change the code of actionCreate like this
public function actionCreate()
    {
        Yii::import('ext.multimodelform.MultiModelForm');
 
        $model = new Group;
 
        $member = new Member;
        $validatedMembers = array();  //ensure an empty array
 
        if(isset($_POST['Group']))
        {
            $model->attributes=$_POST['Group'];
 
            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('create',array(
            'model'=>$model,
            //submit the member and validatedItems to the widget in the edit form
            'member'=>$member,
            'validatedMembers' => $validatedMembers,
        ));
    }
  • Change the renderPartial in views/group/create.php and update.php to transfer the parameters $member and $validatedMembers to the _form.php
echo $this->renderPartial('_form', array('model'=>$model,
                          'member'=>$member,'validatedMembers'=>$validatedMembers));
  • Change the generated code of the GroupController's form view (views/group/_form.php).
<div class="form wide">
 
    <?php $form=$this->beginWidget('CActiveForm', array(
            'id'=>'group-form',
            'enableAjaxValidation'=>false,
    )); ?>
 
    <p class="note">Fields with <span class="required">*</span> are required.</p>
 
    <?php
        //show errorsummary at the top for all models
        //build an array of all models to check
        echo $form->errorSummary(array_merge(array($model),$validatedMembers));
    ?>
 
    <div class="row">
        <?php echo $form->labelEx($model,'title'); ?>
        <?php echo $form->textField($model,'title'); ?>
        <?php echo $form->error($model,'title'); ?>
    </div>
 
<?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(
            'firstname'=>array(
                'type'=>'text',
                'maxlength'=>40,
            ),
            'lastname'=>array(
                'type'=>'text',
                'maxlength'=>40,
            ),
            'membersince'=>array(
                'type'=>'dropdownlist',
                //it is important to add an empty item because of new records
                'items'=>array(''=>'-',2009=>2009,2010=>2010,2011=>2011,),
            ),
        ));
 
    $this->widget('ext.multimodelform.MultiModelForm',array(
            'id' => 'id_member', //the unique widget id
            'formConfig' => $memberFormConfig, //the form configuration array
            'model' => $member, //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' => $member->findAll('groupid=:groupId', array(':groupId'=>$model->id)),
        ));
    ?>
 
    <div class="row buttons">
        <?php echo CHtml::submitButton($model->isNewRecord ? 'Create' : 'Save'); ?>
    </div>
 
    <?php $this->endWidget(); ?>
 
    </div><!-- form -->

Usage Validate/Save

You can split the validate() and save() methods of the Multimodelform to modify the items before saving.

//validate formdata and populate $validatedItems/$deleteItems
    if (MultiModelForm::validate($model,$validatedItems,$deleteItems,$masterValues)) 
    {
 
     //... alter the model attributes of $validatedItems if you need ... 
 
     //will not execute internally validate again, because $validatedItems/$deleteItems are not empty
     MultiModelForm::save($model,$validatedItems,$deleteItems,$masterValues);
    }

Of course you can save() without extra validate before. Validation will be internally done when $validatedItems/$deleteItems are empty.

$validatedItems=array();
 
    if(isset($_POST['FORMDATA']) && MultiModelForm::save($model,$validatedItems,$deleteItems,$masterValues)) 
    {
      //... validation and saving is ok ...
      //redirect ...
    }
 
    //No POST data or validation error on save 
    $this->render ...

Usage tableView

Set the property 'tableView'=>true.

$this->widget('ext.multimodelform.MultiModelForm',array(
           ...
            'tableView' => true,
         //'tableFootCells' => array('footerCol1','footerCol2'...), //optional table footer
           ...
        ));

Usage widget form elements

Yii allows type='AWidget' as form element. So in your form config array you can use:

array(
           'elements'=>array(
                 ....
                  'lastname'=>array(
                    'type'=>'text',
                    'maxlength'=>40,
                    ),
 
                    'dayofbirth'=>array(
                        'type'=>'zii.widgets.jui.CJuiDatePicker',
                        'language'=>'de',
                        'options'=>array(
                            'showAnim'=>'fold',
                        ),
                   ...
                )
            )

This however needs a javascript workaround on cloning the date element. We have to assign the CJuiDatePicker functionality to the cloned new element.

There are the properties jsBeforeClone,jsAfterClone,jsBeforeNewId,jsAfterNewId available where javascript code can be implemented. Use 'this' as the current jQuery object.

For CJuiDatePicker, the extension datetimepicker, CJuiAutoComplete and EJuiComboBox there are predefined functions available, so it's easy to make cloning date fields work.

You have to assign the property 'jsAfterNewId' to the prepared code.

Assume your form definition elements are defined in the array $formConfig. 'afterNewIdDatePicker' reads the options from the specified element and adds the 'datepicker':

$this->widget('ext.multimodelform.MultiModelForm',array(
           ...
             // 'jsBeforeNewId' => "alert(this.attr('id'));",
            'jsAfterNewId' => MultiModelForm::afterNewIdDatePicker($formConfig['elements']['dayofbirth']),
           ...
        ));

Now cloning of the field 'dayofbirth' should work.

Support for

  • datetimepicker: use afterNewIdDateTimePicker()
  • CJuiAutoComplete: use afterNewIdAutoComplete()
  • EJuiCombobox: use afterNewIdJuiComboBox()

For other widgets you have to find out the correct javascript code on cloning. Please let me know if you have found a javascript code for other widgets.

Sortable fieldsets

Set the property 'sortAttribute' to your db-field for sorting (should be an integer) if you want to order the items by drag/drop manually. Uses jQuery UI sortable, but works only when 'tableView' is false. See the demo.

$this->widget('ext.multimodelform.MultiModelForm',array(
           ...
            'sortAttribute' => 'position', //if assigned: sortable fieldsets is enabled
           ...
        ));

Checkboxes

Unfortunatly the basic checkbox is not supported, because it's not so easy to handle (see the comments in the forum).

But if you need checkboxes, you can use the checkboxlist instead. If you only need a single checkbox you can set the item-data to an array with one item.

In the view / formConfig:

$memberFormConfig = array(
          'elements'=>array(
 
             ...
            'flags'=>array(
              'type'=>'checkboxlist',
              'items'=>array('1'=>'Founder','2'=>'Developer','3'=>'Marketing'), //One single checkbox: array('1'=>'Founder')
              ),
        ));

In the model you have to convert array <-> string on saving/loading - see the Member model in the demo

//Convert the flags array to string
    public function beforeSave()
    {
        if(parent::beforeSave())
        {
            if(!empty($this->flags) && is_array($this->flags))
                $this->flags = implode(',',$this->flags);
 
            return true;
        }
 
        return false;
    }
 
    //Convert the flags string to array
    public function afterFind()
    {
       $this->flags = empty($this->flags) ? array() : explode(',',$this->flags);
    }

File fields and file upload

MultiModelForm handles all the stuff with uploading files and images. Assigned images will be displayed as preview, files as download link in the edit form near the upload input.

Add a input element of type 'file' to the form config. It's important to add 'visible'=>true because by Yii default a file field is not safe and unsafe attributes will not be visible.

$memberFormConfig = array(
          'elements'=>array(
            'firstname'=>array(
                'type'=>'text',
                'maxlength'=>40,
            ),
            ...
            'image'=>array(
                  'type'=>'file',
                  'visible'=>true, //Important!
              ),
        ));

Add the image field to the rules of your model. The image is of type file, so a CFileValidator will be used and you can add allowed types, mimetypes, maxSize etc. It's important to set 'allowEmpty'=>true otherwise, the user will be enforced to always upload a new image on updating a record.

public function rules()
    {
 
        return array(
            array('firstname, lastname', 'length', 'max'=>40),
            array('image', 'file', 'allowEmpty'=>true,'types'=>'jpg,gif,png'),
            ...
        );
    }

The file input field in the db must be of type string: VARCHAR(200) or similar to save the relative file path.

Default behavior

The default behavior on uploading is, that mmf will save the uploaded file in the public webroot folder files/modelclass. 'modelclass' is the class of the multimodel (files/member/image1.jpg).

The relative path of the uploaded file will be assigned to the file attribute (image, ...).

Ensure the public folder files is writeable like the assets folder.

MMF takes care about unique filenames in the folder by adding index: filename-1.jpg, filename-2.jpg ... if necessary.

Change default behavior

You can change this default behavior by adding callback methods to your mmf model:

Add a method mmfFileDir() to you mmf model (member,...)

public function mmfFileDir($attribute,$mmf)
    {       
        return 'media/'.strtolower(get_class($this));
    }

The $attribute can be used too, for example if there are multiple file fields in a model. $mmf is the MultiModelForm widget.

Maybe you need another behavior on file upload, for example you want to create image presets (resize, ...) on upload or save the file into the db.

Add a callback method mmfSaveUploadedFile() to the mmf model. The param $uploadedFile is a CUploadedFile instance.

public function mmfSaveUploadedFile($attribute,$uploadedFile,$mmf)
    {       
        if(!empty($uploadedFile))
        {
          $uploadedFile->saveAs(...);
          ... resize or save to db or whatever ...
 
          $this->$attribute = ... path to the preset or other values you like ...    
        }             
    }

If you need access to the mastermodel (group,...) inside this callback methods, you have to assign the new param 'masterModel' in the controller action.

public function actionUpdate($id)
    {
        $model=$this->loadModel($id); //the Group model
 
        $member = new Member;
        $validatedMembers = array(); //ensure an empty array
 
        if(isset($_POST['Group']))
        {
            ...
 
            //the last param $model is the masterModel 'group'.
            if(MultiModelForm::save($member,$validatedMembers,$deleteMembers,$masterValues,$_POST['Member'],$model) 
 
            ...
        }
    ...
    }

Now in your callback methods you can use $groupModel=$mmf->masterModel;

Delete files after removing items

MMF does not delete the uploaded files if items are removed by the user in the edit form. If you want to delete the file after removing items you have to code like below:

if (MultiModelForm::save($model,$validatedItems,$deleteItems,$masterValues)) 
    {
       foreach($deleted as $deletedModel)
       {
          if(!empty($deletedModel->image) && is_file($deletedModel->image))
              unlink($deletedModel->image);
       }             
    }

Attributes for file handling

  • fileReplaceExisting=false: if true, delete existing files with the same name on upload
  • fileImagePreviewHtmlOptions=array('style' => 'max-width: 100px; max-height: 100px;') the html options for the image preview tag in the edit form
  • fileLinkHtmlOptions=array('target'=>'_blank') the htmlOptions for the download link in the edit form

Property showAddItemOnError

Regarding to requests and workarounds in the forum topic:

A user should not be able to add/clone items, when in error mode (model rules not passed successfully). Now you can set the property $showAddItemOnError to false to enable this behavior. See the demo.

Properties allowAddItem and allowRemoveItem (since v3.1)

For example, if you only want to allow an admin user to add new items or remove items, you can use these properties to display the addlink and the removelinks

$this->widget('ext.multimodelform.MultiModelForm',array(
           ...
           'allowAddItem' => Yii::app()->user->isAdmin(),
           'allowRemoveItem' => Yii::app()->user->hasRole('admin'),
           ...
        ));

Bootstrap

Set the property 'bootstrapLayout'=true if you use Twitters Bootstrap CSS or one of the Yii bootstrap extensions.

The formelements/labels will be wrapped by 'control-group', 'controls', ... so that the multimodelform should be displayed correct.

Property jsAfterCloneCallback

If you need to modify the cloned elements or execute js-actions after cloning, you can assign a js function(newElem,sourceElem) as callback.

  • newElem: the new cloned jquery object
  • sourceElem: the clone source object

The callback will be executed for all inputs of a record row.

Usage:

// a js function in your view
    echo CHtml::script('function alertIds(newElem,sourceElem) { 
        alert(newElem.attr("id"));
        alert(sourceElem.attr("id"));}'
    );
 
    $this->widget('ext.multimodelform.MultiModelForm',array(
      ...
       'jsAfterCloneCallback'=>'alertIds',
      ...
    ));

Notes

  • If you upgrade MultiModelForm, don't forget to delete the assets.

  • You can use multiple MultiModelForm widgets in a view, but the mmf models MUST be of different classes. Take care to assign a unique widget id when adding more multimodelform widgets.

  • Take a look at MultiModelForm.php for more options of the widget.

  • The widget never will render a form begin/end tag. So you have always to add $this->beginWidget('CActiveForm',...) ... $this->endWidget in the view.

  • The implementation of the class MultiModelEmbeddedForm needs review in upcoming Yii releases. In 1.1.6+ the only output of CActiveForm.init() and CActiveForm.run() is the form begin and end tag.

  • The extension should work for non activerecord models too: instances of CModel, CFormModel...

  • Use Yii::app()->controller->action->id or $model->scenario to generate different forms for your needs (readonly fields on update ...)

Ressources

Changelog

  • v6.0.0 Support for filefields with handling the fileupload and preview
    • new parameter $initAttributes for method validate()
    • new parameter $masterModel for method save()
    • Added composer support / composer.json
    • internal changes and minor bugfixes
  • v5.0 better custom js handling please see comments in the code; don't forget to clear assets after update
    • new property 'removeOnClick' to exec js code on clicking the remove link
    • new property 'jsAfterCloneCallback' - usage: see documentation above
    • new property 'clearInputs' (= options['clearInputs'], default true) with bugfix on cloning values
    • new property 'jsRelCopy' to use your own modified jsrelcopy js-script (placed in assets folder)
  • v4.5
    • added support for composite pk
    • new property 'renderForm' allows a custom 'MultiModelRenderForm'
    • changed update behavior: loads the record from the db by findByPK before update (like default behavior of actionUpdate in a controller)
  • v4.1
    • Bugfix: rendering tableView with Bootstrap layout
  • v4.0

    • Bugfix: two remove columns in tableview when hideCopyTemplate=true. Many thanks to shoemaker. See this forum topic
    • Support for Twitters Bootstrap
    • New property 'addItemAsButton' to show a button 'Add item' instead of a link.
    • Minor bugfix in js-code
  • v3.3

    • Correct support for the options['limit'] property from relcopy.js. See property limitText.
  • v3.2
    • New property 'hideCopyTemplate' (default:true), means that the empty copyTemplate is not visible
    • New demo with CheckBoxList
  • v3.1
    • New: Added properties $allowAddItem and $allowRemoveItem
    • Bugfix: hidden fields in the Tableheader no more displayed
    • Bugfix: Strings as elements formconfig (htmlttags,CFormStringElement) have not been rendered
  • v3.0

    • New: Added sortable feature for fieldsets (not in table view)
    • New: Property $showAddItemOnError=true; Show 'Add item' link and empty item in errormode
    • New: Demo with sortable fieldsets
    • Bugfixes: visible/hidden fields
  • v2.2.1 Bugfix: Array elements need extra 'allEmpty' check 

  • v2.2
    • Support for array elements (checkboxlist, radiolist) in form config These elements didn't work on creating only on update
  • v2.1.1
    • Bugfix - Labels of hidden elements have been rendered
  • v2.1
    • Bugfix - tableView: Hidden input have been rendered into a cell
    • Changed parameters and handling of MultiModelForm::save
  • v2.0.1 Bugfix: Tableheader displayed hidden fields too. Better internal handling of labels, now supports required '*'
  • v2.0 Added 'tableView' and support for cloning date/time widgets
  • v1.0.2 Bugfix: Detailrecord was created twice on creating master
  • v1.0.1 Bugfix 'Undefined Index','Undefined variable' when error_reporting(E_ALL) is set

Total 20 comments

#18624 report it
bhushanlambat at 2014/12/02 11:29pm
Dependent Drop Down

Shall I use dependent drop down in following coding

$memberFormConfig = array( 'elements'=>array( 'firstname'=>array( 'type'=>'text', 'maxlength'=>40, ), 'lastname'=>array( 'type'=>'text', 'maxlength'=>40, ), 'membersince'=>array( 'type'=>'dropdownlist', //it is important to add an empty item because of new records 'items'=>array(''=>'-',2009=>2009,2010=>2010,2011=>2011,), ), ));

Please reply and guide me.... I am new in Yii

#18593 report it
myrazel at 2014/11/25 06:46am
Incompatible with Chosen

I have problem when implement it with chosen, probably adding this feature will be great?

#17929 report it
pou77 at 2014/08/12 06:29am
Including row numbers?

This is my first extension to implement while learning YII and I must say I can't see developing without it. It's also pretty easy to follow. But, how can I have the row number populate a text field value? I can find the mmfRecordCount variable in the .js and MultiModelForm.php files but my newbie skills lack the ability to access it when clicking the 'Add Item'.

For example:

$hhmembersFormConfig = array(
   'elements'=>array(
   'hh_member_no'=>array(
      'type'=>'text',
      'maxlength'=>40,
      'disabled'=>true,
      'value'=>$row, // or item number count
    ),

When I click on 'Add Item' I would like the household member number (hh_member_no) to be 1,2,3,etc.

Thanks!

#17297 report it
Alex D. at 2014/05/20 06:32am
[SOLVED] One more problem...

Sorry for asking, but it seems to me that there's little bug in extension. When I use 1 JuiAutocomplete in a row - everything is ok. But when I add one more JuiAutocomplete (for another field in the same child table) something goes wrong after I begin to ADD ROWS. Both different autocompletes in first row search perfectly (and separately). But in all added AFTER first row lines both autocompletes are searching the same source url - looks like it copies only 1st autocomplete (they look separate but the functioning is like it's the same instance).

$memberFormConfig = array(
            'elements'=>array(
 
              'invent_num_and_title'=>array(
                'type'=>'zii.widgets.jui.CJuiAutoComplete',
                'source'=>Yii::app()->createUrl('/inventory/inventcard/searchInventCard'),
                'options'=>array(
                    'showAnim'=>'fold',
                    'select' =>'js: function(event, ui) {
                          this.value = ui.item.value;
                          return false;
                      }',
                ),
                ),
 
 
              'department_to'=>array(
                'type'=>'zii.widgets.jui.CJuiAutoComplete',
                'source'=>Yii::app()->createUrl('/personnel/department/searchDepartment'),
                'options'=>array(
                    'showAnim'=>'fold',
                    'select' =>'js: function(event, ui) {
                          this.value = ui.item.value;
                          return false;
                      }',
                ),
                ),
 
          ));

and the way I add them to _form:

'jsAfterNewId'=>MultiModelForm::afterNewIdAutoComplete($memberFormConfig['elements']['invent_num_and_title']) . MultiModelForm::afterNewIdAutoComplete($memberFormConfig['elements']['department_to']),

Can please try to use 2 seperate autocompletes (try >1 rows copied) to check is this is an issue? Or tell me where's my fault...

[UPDATE] YES! I'm newbie in JS so it took me more than 3 hours to fix this issue. One of the possible problem with my approach - is that 'afterNewIdAutoComplete' function somehow double-overwrite properties each time I add new row. So I decided to check only 'proper' objects (to put some filter to afterNewIdAutoComplete function). In order to do that 1) I've added new property to JUIAutocomlete config 'common_id_string' as a common string part of all id's of that particular field (generally - I duplicate element's name):

...
'invent_num_and_title'=>array(
                'type'=>'zii.widgets.jui.CJuiAutoComplete',
                'source'=>Yii::app()->createUrl('/inventory/inventcard/searchInventCard'),
                'options'=>array(
                    'showAnim'=>'fold',
                    'common_id_string'=>'invent_num_and_title', // I declared it once more to have access to it in JS function
...
// did the same but with  with 'common_id_string'=>'department_to'

2) then I've changed one line in afterNewIdAutoComplete function (MultiModelForm.php:419)

return "if ( this.hasClass('ui-autocomplete-input') && this[0].id.indexOf('{$element['options']['common_id_string']}')>=0 )

And it worked perfectly! If there's more elegant way to do it, please inform me. Maybe it would be very helpful to integrate some type of this problem's solution in future release of MMF. Thank you!

#17295 report it
Alex D. at 2014/05/20 04:34am
Thanx!

Thanx Joblo for the hint! I had 5.0 version and it duplicated "remove" link (in bootstrap, table mode) too many times each line you add. Then I've updated to 6.0 and GREAT- you fixed this issue! ;) Thanx again!

#17292 report it
Joblo at 2014/05/20 03:04am
One row visible

You have to set the attribute 'hideCopyTemplate'=>false, default is true. This will always add an empty row = the row that will be cloned by js.

$this->widget('ext.multimodelform.MultiModelForm',array(
             ... 
            'hideCopyTemplate' => false, 
             ...        
        ));
#17290 report it
Alex D. at 2014/05/20 02:17am
Initial setup option

Thanks for the extension! Is there any chance to setup initial number of rows in MMF? It starts with no child rows, but in general case there always should be at least 1.

#16684 report it
ajobegs at 2014/03/19 02:53am
3 member in one Group

is it possible to build 3 member in one form??

#16203 report it
skworden at 2014/01/27 10:32pm
Template?

Is there anyway to use a template for the fields? I want to wrap them inside multiple divs and span classes. i.e. like this

<div class="col-md-4">
        <div class="input-icon">
                <label class="control-label"><?php echo $form->labelEx($model,'state'); ?></label>
                <i class="fa fa-home"></i>
                <?php echo $form->dropDownList($model, 'state', CHtml::listData( States::model()->findAll(),
                'id', 'state'),array('class'=>'form-control', 'prompt' => 'Select a State','maxlength'=>2, 'style'=>'padding-left:30px;')); ?>
        </div>
        <span class="help-block">
                <?php echo $form->error($model,'state'); ?>
        </span>
</div>

Also how do you get the id for the item? i want to get it to show related data on the form.

#16202 report it
skworden at 2014/01/27 10:28pm
FYI

First of all great extension. It works great and saved me tons of time.

In action update / create with a drop down it kept inserting a new row into my database even though my items were not set to add them in the form on my dropdown. i had to change your example for action update/ create to check if my field had an input.

public function actionUpdate($id)
    {
        Yii::import('ext.multimodelform.MultiModelForm');
 
        $model=$this->loadModel($id); //the Group model
 
        $physician = new PatientsPhysician;
        $validatedPatientPhysician = array(); //ensure an empty array
 
       if(isset($_POST['Patients']))
        {
            $model->attributes=$_POST['Patients'];
 
            //the value for the foreign key 'physician_id'
            $masterValues = array ('patient_id'=>$model->id);
 
                /* check to see if field is set on dropdown*/
            if(isset($_POST['PatientsPhysician']['physician_id']))
            {
                if( //Save the master model after saving valid physicians
                    MultiModelForm::save($physician,$validatedPatientPhysician,$deleteMembers,$masterValues) &&
                    $model->save()
                   )
                $this->redirect(array('view','id'=>$model->id));
            }
            if($model->save()){
                $this->redirect(array('view','id'=>$model->id));
            }
        }
 
        $this->render('update',array(
        'model'=>$model,
        //submit the physician and validatedItems to the widget in the edit form
        'physician'=>$physician,
        'validatedMembers' => $validatedPatientPhysician,
        ));
    }

and my view is as follows

<?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
 
$paitentFormConfig = array(
      'elements'=>array(
 
        'physician_id'=>array(
            'type'=>'dropdownlist',
            'empty'=>'  ',
            //it is important to add an empty item because of new records
            'items'=>CHtml::listData( Physician::model()->findAll(), 'id', 'first_name'),
        )),
);
 
$this->widget('ext.multimodelform.MultiModelForm',array(
        'id' => 'id_physicians', //the unique widget id
        'formConfig' => $paitentFormConfig, //the form configuration array
        'model' => $physician, //instance of the form model
 
        //if submitted not empty from the controller,
        //the form will be rendered with validation errors
        'validatedItems' => $validatedMembers,
        'tableView' => false, //sortable will not work
            'fieldsetWrapper' => array('tag' => 'div', 'htmlOptions' => array('class' => 'col-md-3')),
            'removeLinkWrapper' => array('tag' => 'div', 'htmlOptions' => array('class'=>'red', 'style'=>' color: ffffff;')),
            'removeHtmlOptions'=>array('class'=>'portfolio-btn', 'style'=>' color: ffffff;'),
            'addItemText' => 'Add Physician',
            'removeText' => 'Remove Physician', 
            'removeConfirm' => 'Are you sure you want to remove this physician?', 
        //array of member instances loaded from d
        'data' => $physician->findAll('patient_id=:patientId', array(':patientId'=>$model->id)),
    ));
?>
#15857 report it
Joblo at 2013/12/23 03:43am
display errors

An input error (generated by the model rules) should be displayed near the fields too, not only in errorSummary.

Did you check the demo, leaving lastname of the member blank (is required in model rules)?

#15855 report it
mem at 2013/12/22 06:18pm
Validation near fields

If instead of using:

echo $form->errorSummary(array_merge(array($model),$validatedMembers));

We wish to display the error messages near each field on the form. Is this possible to accomplish? Lets say we have a form with Team and Members, and for each member, that a user can add or remove via ajax, if they are filled in and present, we wish to validate them and display the error near those form fields. Is this possible?

Thanks.

#15225 report it
bvpk at 2013/10/19 03:56am
problem with delete.

first of all thank to your work. i have one problem when delete group , it will provide problem for me.

#15169 report it
nat3863 at 2013/10/14 11:51am
ID number of cloned elements.

Hi Joblo. Thanks. But I would like to specifically get the ID number for a specific element. For example, if I have one field that which its id called Text_field, I would to get the number of the ID after it has been cloned. e.g.:

Text_field
Text_field1
Text_field2
#15163 report it
Joblo at 2013/10/14 05:24am
Id of cloned elements

You can register a js-function 'jsAfterCloneCallback' since v5.0.

See the example for the property jsAfterCloneCallback in the documentation above.

#15162 report it
nat3863 at 2013/10/14 04:04am
Getting ID number of cloned elements.

Hi, any idea how I can get id number of cloned elements? Thank you!

#14589 report it
ajobegs at 2013/08/26 02:51am
Many members

Hello All. I have the database

==== Class Group ====
     id
     name
 
     ==== Member1 ====
     id
     group_id
     Teacher
 
   ==== Member2 ====
     id
     group_id
     Student
 
   ==== Member3 ====
     id
     group_id
     Course

My Question is how to create more than 1 member instance.

for example :

public function actionCreate()
  {
    $model=new Group;
    $member1=new Member1;
     $member2=new Member2;
     $member3=new Member3;
     $member4=new Member4;
     ....//and other more than 10 members
#14566 report it
fart at 2013/08/23 08:10am
Update a field

All this I ask is because I try to update a field in the same row (by js) once enter a value in another and I do not know how to do if the Id of the fields are duplicated from one row to another when you delete a row except the last. Any suggestions?

Anyway, thank you very much JoBlo, for this great extension

#14555 report it
Joblo at 2013/08/22 08:50am
removeLink

Your wishes are very specific, I don't know how to implement this generally.

The best is, you create your own MultiModelForm widget, that inherits MultiModelForm and override the methods you need. Search for the getRemoveLink method in your code to see where/when the removelink is rendered.

#14553 report it
fart at 2013/08/22 08:38am
Deleting a row

Hello, Can I restrict the deletion to the last row inserted ? Only the last one.

Leave a comment

Please to leave your comment.

Create extension