title: Tapestry 5.3: Component with form inside t:zone
body: <p>I have a component for editing db entity. It has @CommitAfter on onSuccess().  When it is on the separate page it works fine. I click update button, it saves data and redirects to view page.</p>
  
  <p>Now I want to reuse it on the list page. By clicking on item it should appear. After editing and clicking update button on the component it should save item to db and hide itself.</p>
  
  <p>To achieve this I modified component so I can set zone id for its form. Put component inside zone on the list page, added links for each item with event onSelectItem, which sets zone id for component and returns body of the zone.</p>
  
  <p>It did show component and I could edit fields and hit update button. It updated item but redirected whole page to view page.  I tried to return null in onSuccess() – but in this case it didn’t save data to db and zone also wasn’t refreshed. I also tried call page class from a component by using @InjectPage and return page.zone.getBody() – this does reload zone but still doesn’t save data though all methods passed w/o exception. Also it too bad to call page specific code inside a component. My other custom ajax calls do save data to db in methods with @CommitAfter.</p>
  
  <p>So my question what is the correct way of doing this in Tapestry?</p>
  
  <p>ContactsList.tml</p>
  
  <pre><code>&lt;html t:type="layout" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd" xmlns:p="tapestry:parameter"&gt;
      &lt;t:form&gt;
         ... list of contacts linked to onSelectContact()
      &lt;/t:form&gt;
  
      &lt;t:zone id="editContact" t:id="editContactZone"&gt;
          &lt;t:if test="selectedContact"&gt;
              &lt;t:contactform t:id="contactForm" /&gt;
          &lt;/t:if&gt;
      &lt;/t:zone&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>ListPage.java</p>
  
  <pre><code>public class ContactsList{
      @InjectComponent
      private Zone editContactZone;
  
      @InjectComponent("contactForm")
      private ContactForm contactForm;
  
      @Property
      private Contact selectedContact;
  
      public Object onSelectContact(@RequestParameter(value = "id", allowBlank = false) Integer id) {
          selectedContact = getContactById(id);
          if (selectedContact != null) {
              contactForm.setContact(selectedContact);
              contactForm.setFormZone(editContactZone.getClientId());
          }
  
          return editContactZone.getBody();
      }
  }
  </code></pre>
  
  <p>ContactForm.tml</p>
  
  <pre><code>&lt;div xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd" xmlns:p="tapestry:parameter"&gt;
  
      &lt;t:form t:id="editContactForm" zone="prop:zone"&gt;
          .... contact fields
      &lt;/t:form&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p>ContactForm.java</p>
  
  <pre><code>public class ContactForm{
      @InjectComponent("editContactForm")
      private Form editContactForm;
  
      @Property
      private String zone;
  
      @InjectPage
      private ContactList listPage;
  
      @InjectPage
      private ViewContact viewContact;
  
      @Property
      protected Contact contact;
  
      public void setContact(Contact contact) {
          this.contact = contact;
      }
  
      public void setFormZone(String zone){
         this.zone = zone;
      }
  
      @CommitAfter
      public Object onSuccess() {
         parseContact();
         storeContact(); // calls DAO.store(contact)
  
         return zone == null ? viewContact : listPage.onSelectContact(0); //don't like this in component code but at least it returns zone's body 
      }
  }
  </code></pre>