Repeated forms on the same page

Often you want the user to have a form not just for one entity but for all of them on the same page. A form for each product in the same category, for example. I’m not talking about multiple different forms but multiple instances of the same form.

This topic has been discussed in the Nette forum so many times that it’s really a shame that it’s still missing in the documentation. Frustrated after an hour spent reading outdated forum posts, I offer here a complete solution based on one of the posts.

Form definition goes into /app/forms/ProductForm.php

  1. class ProductForm extends NAppForm {
  2.   var $parent; // used in process()
  3.  
  4.   public function __construct($parent = null, $name = null) {
  5.     parent::__construct($parent, $name);
  6.     $this->parent = $parent;
  7.  
  8.     $this->addText(‘title’, ‘Heading:’);
  9.     $this->onSuccess[] = callback($this, ‘process’);
  10.   }
  11.  
  12.   public function process($form) {
  13.     $values = $form->getValues();
  14.     $this->parent->flashMessage(‘Product saved.’);
  15.     $this->parent->redirect();
  16.   }
  17. }

Here’s how you use it in your presenter:

  1. class ProductPresenter extends NPresenter {
  2.  
  3.   // this needs to go into action, not render
  4.   public function actionDefault() {
  5.     $products = …;
  6.  
  7.     foreach ($products as $product) {
  8.       $this->_createProductForm($product);
  9.     }
  10.  
  11.     $this->template->products = $products;
  12.   }
  13.  
  14.   protected function _createProductForm($product) {
  15.     $form = new ProductForm($this, ‘ProductForm_’.$product[‘id’]);
  16.     $form->setDefaults($product);
  17.   }
  18.  
  19. }

And the final piece of the puzzle, your template:

  1. New product form:
  2. {form ProductForm}
  3.   {label title /} {input title, autofocus => TRUE}
  4.   {input save, value => ‘Create’}
  5.   <br />
  6.   {input body}
  7. {/form}
  8.  
  9. <hr />
  10.  
  11. Existing products:
  12. {foreach $products as $product}
  13.   {var formName = ‘ProductForm_’ . $product[‘id’]}
  14.   {form $formName}
  15.     {label title /} {input title}
  16.     {input save}
  17.     <br />
  18.     {input body}
  19.   {/form}
  20. {/foreach}
  21.  

As always, if it doesn’t work for you, check your Nette version and compare it with the tag below.

Tags:

2 Responses to “Repeated forms on the same page”

  1. var $parent; ?? You can always call $this->getParent() in components, or even better, you can call $this->getPresenter().

    And the whole foreach thing and name composition is unnecessary. You can filter components by type http://pastebin.com/TYr9nUjB

  2. Thanks! I really wish this stuff was in the documentation.

    A note for everyone: Please don’t suggest that I add it to the docs myself. These guys have their own funny rules for what should be included and what shouldn’t.

Leave a Reply