[EXTENSION] multimodelform/jqrelcopy

I start a topic here, better than to discuss all the stuff about cloning fields at the extension pages.

Hi Joblo,

Thanks for putting together multimodelform. I got it set up and working and it is a huge help but confused about a simple aspect of it.

Using the example group::member that you have posted I have set up group.id as INT with Auto Increment and then formed a relation from member.groupid to group.id and changed my widget(‘ext.multimodelform.MultiModelForm’,array( to match.

On my form I have Tile, Firstname, Lastname, Member Since as expected but there is also labels for ID and GroupId below them.

What do I need to modify to remove these labels from attributes where I am not collecting any data in the form? I understand how to handle all of this in a normal form but having problems making sense of the logic in your extension.

I had this issue too and hoped to eliminate this behavior.

I will upgrade soon to v2.2

You have to change the code in line 843 with this.




if ($this->isCopyTemplate)// new fieldset

				{

					$element->name = $elemName . '[]';

					$elemOutput = ($element->type == 'hidden' || //bugfix: v2.2

						          $this->parentWidget->tableView) ? '' : $elemLabel;


					$elemOutput .= $element->render();

					//bugfix: v2.1 - don't render hidden inputs in table cell

					$output .= $element->type == 'hidden' ? $elemOutput :$this->getWrappedRow($elemOutput);


				}

....



Perfect, that does the trick. Thanks for the quick reply and help.

Hi again Joblo,

I was wondering if you had an example of using this with 3 or more forms?

Extending from your Group::Member example if there was a relationship Member::Profile how could I get the Profile form elements to also show up on the Group form? In my app (using my tables of course), I have used multimodelform to create forms for both Group::Member and Member::Profile but I am assuming I need to form some arrays with actionCreate and actionUpdate of the GroupController to make this happen to have Profile elements directly on the Group form, correct? I have tried a few different things and even tried pulling the logic from what qiang had written here. Anyways wondering if you have an example.

Thanks

Sorry, there’s no example for 3 or more forms.

But it works.

In a project I use an array of multimodelforms to render into a form (database is mongoDB).

For the profile you have to place a second multimodelform widget with another id and own validatedItems.

In the controller you have to handle extra validate / validatedItems / deleteItems.

It’s similar to the wike-doc from qiang.

Hope the helps.

Ok I worked through it now. I had a problem with my relationships. I now have multiple forms displaying but can’t fully test create and update until I clear up some things in my db.

I have extend the Multi model form extension to support File Upload field.

Currently, you can only use ‘type’ => ‘file’ in your form config to add an upload field to your dynamic form.

I’ll try with CMultiUpload widget later.

1774

multimodelform.zip

When an error occurs on a form that form is then copied and placed under the original one and is blanked out. Can I change this behavior to not create a copied instance of the form and just use the original form to reinput their data?

I am not sure if the method run() is causing this?

I don’t know why if an element does not in the form config, you have to write it as “hidden” type?

Just delete all of those element and using $model->setAttributes() should be enough, right?

@dinhtrung

thanks for your code.

In the method ‘renderFormElements()’ I use




$elements = $this->getElements();

  foreach($elements as $element)

                .... 



I was surprised that Yii returns all model attributes, not only the elements from the form config.

But maybe it’s not bad when other elements were rendered as hidden to ensure data integrity …

@enfield

I always add an empty ‘CopyTemplate’, even in validatation mode. Maybe the user want to correct errors add more items …

See method ‘run()’




 ....

	// add an empty fieldset as CopyTemplate

	$form = new MultiModelRenderForm($this->formConfig, $this->model);

	$form->index = $idx;

	$form->parentWidget = $this;

	$form->isCopyTemplate = true;

 ...



Is it that what you mean with copied and blanked out?

Joblo, sometimes it is easier to explain through pictures…

Sure I want the user to be able to correct their information but not through the second copy of the model (Member). I want them to be able to correct directly in the place where the mistake occurred. In the case above in the red shaded box of Firstname.

I have been trying to modify you method run() even before posting my original question but can’t seem to be getting anything working.

Ok not sure what I am not understanding here. With relCopy does the behavior I mentioned have to happen? I have been chasing my tail trying to figure out the behavior but am not getting anywhere. I would appreciate any help.

As I understand, if the validation failed, you don’t want the Multi model form to add another blank form after the last subform. You just like the form to appear like it is, before click the “Save” button, right?

Unfortunately, this is not possible. The extension automatically create a sub form with the config provided, as a source for jQuery Relcopy to create new ones when click the Add Item.

Using CForm 's showErrorSummary setting (read Yii api about this), you can make the subform display its own error. By default, the extension return the error to Member model, so when validation failed, there is only one error Summary display on top of the form.

If you want you can display the CopyTemplate and the AddItem link only if not in errormode:

The form is in displaying errors mode if the validated items are not empty.




public function run()

{

 

 $isErrorMode = !empty($this->validatedItems);


    ...


   // add an empty fieldset as CopyTemplate

  if (!$isErrorMode) //some invalid models exists

  {

    $form = new MultiModelRenderForm($this->formConfig, $this->model);

    $form->index = $idx;

    $form->parentWidget = $this;

    $form->isCopyTemplate = true;

		

    if (!$this->tableView)

    {

	if ($idx == 0) // no existing data rendered

	echo $form->renderAddLink();

     }

		

     echo $form->render();

  } 

  ...



Then you have to render the addlink only if the CopyTemplate is shown.





 if ($idx == 0 && !$isErrorMode) // no existing data rendered

	echo $form->renderAddLink();




Maybe I will add this feature configurable in the widget.

But in my opinion a user should be able to add more items also when other fields show errors.

And the AddItem link needs a empty CopyTemplate to clone…

dinhtrung and Joblo,

Thanks for the response. Maybe I didn’t fully appreciate the purpose of this extension. In my app I have changed my user forms to a more basic approach but can still utilize the functionality of this app in my admin forms.

I’m having some issues with checkboxes. It appears the jQuery addon doesn’t copy the hidden field Yii generates so that an unchecked box is 0 rather than blank.

I fixed it for myself by adding a custom validation rule that sets the field to 0 if it is null, but it would be better if the hidden field was copied. (It works right for each row generated server side, just not for extra rows added client side.)

Below is an example using Multimodelform to handle Upload files.

I create a new AR model to store files, and use Multimodel Form to handle the form.

Hi Friends,

Hope it’s the right place to ask questions about jqrelcopy extension. Couple of things i don’t know how to do with this extension.

  1. Is it possible to assign new id’s to the fields everytime when we do the cloning ?

  2. In update mode, how to add "remove" link for the cloned rows ?

Appreciate your help on this .Thanks in advance.

  1. By default the id of the cloned element is incremented by javascript with a counter,no need to do it manually.

See the code of ‘jquery.relcopy.yii.1.0.js’:




	                       // 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));

				});




If you want to change this behavior (necessary when cloning dateTimePicker …),

you can add a js-code as option for ‘jsBeforeNewId’ or ‘jsAfterNewId’ on cloning to alter the id in another way.




$this->widget('ext.jqrelcopy.JQRelcopy',

array(

      'id' => 'copylink',

      'removeText' => 'Remove this item',

      'jsBeforeNewId' => "alert(this.attr('id'));",

      'jsAfterNewId' => "this.attr('id','myNewId'); alert(this.attr('id'));",

      ));




  1. The remove link should be there if you add a ‘removeText’ option like above.