Author: hlship
Date: Mon Nov 10 11:53:58 2008
New Revision: 712816

URL: http://svn.apache.org/viewvc?rev=712816&view=rev
Log:
TAP5-12: Need better docs for AjaxFormLoop; component should link to AddRowLink 
and RemoveRowLink, and need some examples

Added:
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/AjaxFormLoop.xdoc
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/ajaxformloop.png
   (with props)
Modified:
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/AjaxFormLoop.java

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/AjaxFormLoop.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/AjaxFormLoop.java?rev=712816&r1=712815&r2=712816&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/AjaxFormLoop.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/AjaxFormLoop.java
 Mon Nov 10 11:53:58 2008
@@ -31,8 +31,8 @@
 import java.util.Iterator;
 
 /**
- * A special form of the [EMAIL PROTECTED] 
org.apache.tapestry5.corelib.components.Loop} component that adds a lot of Ajax 
support
- * to handle adding new rows and removing existing rows dynamically.  Expects 
that the values being iterated over are
+ * A special form of the [EMAIL PROTECTED] 
org.apache.tapestry5.corelib.components.Loop} component that adds  Ajax support 
to
+ * handle adding new rows and removing existing rows dynamically.  Expects 
that the values being iterated over are
  * entities that can be identified via a [EMAIL PROTECTED] 
org.apache.tapestry5.PrimaryKeyEncoder}.
  * <p/>
  * Works with [EMAIL PROTECTED] 
org.apache.tapestry5.corelib.components.AddRowLink} and [EMAIL PROTECTED]

Added: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/AjaxFormLoop.xdoc
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/AjaxFormLoop.xdoc?rev=712816&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/AjaxFormLoop.xdoc
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/AjaxFormLoop.xdoc
 Mon Nov 10 11:53:58 2008
@@ -0,0 +1,319 @@
+<document>
+    <body>
+        <section name="Related Components">
+
+            <ul>
+                <li>
+                    <a href="AddRowLink.html">AddRowLink</a>
+                </li>
+                <li>
+                    <a href="RemoveRowLink.html">RemoveRowLink</a>
+                </li>
+                <li>
+                    <a href="Loop.html">Loop</a>
+                </li>
+                <li>
+                    <a href="FormInjector.html">FormInjector</a>
+                </li>
+            </ul>
+        </section>
+
+        <section name="Examples">
+
+            <p>
+                AjaxFormLoop renders an extensible, editable list of entities. 
It is intended for use with Master/Detail
+                relationships
+                (such as between an Order and a LineItem, in an e-commerce 
application). It allows new detail objects
+                to be added on the server side, with corresponding new user 
interface added to the client side.
+                Likewise,
+                existing server-side objects can be removed, and the 
corresponding user interface also removed.
+            </p>
+
+            <p>
+                AjaxFormLoop is dependent on the ability to extract an 
identifier (a primary key) from objects when
+                rendering, and
+                then retrieve the full object in a later request, such as when 
the form is submitted. This aligns well
+                with
+                an Object Relational Mapping layer such as Hibernate.
+            </p>
+
+
+            <p>
+                This example has an address book of Persons, each of which has 
multiple Phones. It is, in fact,
+                implemented in terms of Hibernate, using the 
tapestry-hibernate module.
+            </p>
+
+            <img src="ajaxformloop.png"/>
+
+
+            <subsection name="Person.java">
+                <source><![CDATA[package org.example.addressbook.entities;
+
+import org.apache.tapestry5.beaneditor.NonVisual;
+import org.apache.tapestry5.beaneditor.Validate;
+import org.apache.tapestry5.beaneditor.Width;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+
+import javax.persistence.*;
+import java.util.List;
+
[EMAIL PROTECTED]
+public class Person
+{
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    @NonVisual
+    private long id;
+
+    . . .
+
+    @OneToMany(mappedBy = "person", cascade = CascadeType.ALL)
+    private List<Phone> phones = new ArrayList<Phone>();
+
+    . . .
+
+    public List<Phone> getPhones()
+    {
+        return phones;
+    }
+
+    public void setPhones(List<Phone> phones)
+    {
+        this.phones = phones;
+    }
+}
+]]></source>
+            </subsection>
+
+            <subsection name="PhoneType.java">
+                <source><![CDATA[package org.example.addressbook.entities;
+
+public enum PhoneType
+{
+    HOME, OFFICE, MOBILE, FAX, PAGER
+}
+]]></source>
+            </subsection>
+
+            <subsection name="Phone.java">
+                <source><![CDATA[package org.example.addressbook.entities;
+
+import org.apache.tapestry5.beaneditor.NonVisual;
+import org.apache.tapestry5.beaneditor.Validate;
+import org.apache.tapestry5.beaneditor.Width;
+
+import javax.persistence.*;
+
[EMAIL PROTECTED]
+public class Phone
+{
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    @NonVisual
+    private long id;
+
+    @ManyToOne(optional = false)
+    private Person person;
+
+    private PhoneType type;
+
+    @Column(nullable = true, length = 20)
+    @Width(20)
+    @Validate("required,maxlength=20")
+    private String number;
+
+    public long getId()
+    {
+        return id;
+    }
+
+    public void setId(long id)
+    {
+        this.id = id;
+    }
+
+    public Person getPerson()
+    {
+        return person;
+    }
+
+    public void setPerson(Person person)
+    {
+        this.person = person;
+    }
+
+    public PhoneType getType()
+    {
+        return type;
+    }
+
+    public void setType(PhoneType type)
+    {
+        this.type = type;
+    }
+
+    public String getNumber()
+    {
+        return number;
+    }
+
+    public void setNumber(String number)
+    {
+        this.number = number;
+    }
+}
+]]></source>
+                <p>Notice that the number field is nullable but required. This 
is because, when creating a new Phone
+                    instance, we have no number to fill in.
+                    However, a number is expected, and the user interface 
enforces that.
+                </p>
+            </subsection>
+
+            <subsection name="Edit.tml">
+                <source><![CDATA[<html 
xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd";>
+  <body>
+    <h1>Edit ${person.firstName} ${person.lastName}</h1>
+
+    <t:form t:id="form">
+
+      <t:errors/>
+
+      <div class="t-beaneditor">
+
+        <t:beaneditor t:id="person"/>
+
+        <h2>Phones</h2>
+
+        <div t:type="ajaxformloop" t:id="phones" source="person.phones" 
encoder="phoneEncoder" value="phone">
+          <t:select t:id="type" value="phone.type"/>
+          <t:textfield t:id="number" value="phone.number"/>
+
+          |
+
+          <t:removerowlink>remove</t:removerowlink>
+
+
+        </div>
+
+        <p>
+          <input type="submit" value="Update"/>
+        </p>
+      </div>
+    </t:form>
+
+  </body>
+</html>]]></source>
+
+                <p>
+                    Here we're editting the direct properties of the Person 
object and adding a section below to allow
+                    the phones for the person to be editted. The AjaxFormLoop 
looks much like a Loop component here,
+                    except we must provide a PrimaryKeyEncoder object.
+                </p>
+
+                <p>
+                    Each row provides a RemoveRowLink component that will 
remove that row (from the server side, then on
+                    the client side).
+                </p>
+
+                <p>
+                    The AjaxFormLoop provides a default row for adding 
additional data rows.
+                </p>
+
+
+            </subsection>
+
+            <subsection name="Edit.java">
+                <source><![CDATA[package org.example.addressbook.pages;
+
+import org.apache.tapestry5.PrimaryKeyEncoder;
+import org.apache.tapestry5.annotations.PageActivationContext;
+import org.apache.tapestry5.annotations.Property;
+import org.apache.tapestry5.hibernate.annotations.CommitAfter;
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.example.addressbook.entities.Person;
+import org.example.addressbook.entities.Phone;
+import org.hibernate.Session;
+
+import java.util.List;
+
+public class Edit
+{
+  @PageActivationContext
+  @Property
+  private Person person;
+
+  @Property
+  private Phone phone;
+
+  @Inject
+  private Session session;
+
+  public PrimaryKeyEncoder<Long, Phone> getPhoneEncoder()
+  {
+    return new PrimaryKeyEncoder<Long, Phone>()
+    {
+      public Long toKey(Phone value)
+      {
+        return value.getId();
+      }
+
+      public void prepareForKeys(List<Long> keys)
+      {
+      }
+
+      public Phone toValue(Long key)
+      {
+        return (Phone) session.get(Phone.class, key);
+      }
+    };
+  }
+
+  @CommitAfter
+  public Object onSuccess()
+  {
+    return Index.class;
+  }
+
+  @CommitAfter
+  Object onAddRowFromPhones()
+  {
+    Phone phone = new Phone();
+
+    person.getPhones().add(phone);
+    phone.setPerson(person);
+
+    return phone;
+  }
+
+  @CommitAfter
+  void onRemoveRowFromPhones(Phone phone)
+  {
+    session.delete(phone);
+  }
+}
+]]></source>
+            </subsection>
+
+            <p>
+                The onAddRowFromPhones() event handler method's job is to add 
a new Phone instance and
+                connect it to the Person. The @CommitAfter annotation ensures 
that changes are saved
+                to the database (including generating a primary key for the 
new Phone instance).
+            </p>
+
+            <p>
+                The flip side is onRemoveRowFromPhones(), which is the event 
handler when removing a row.
+                The event handler method is passed the Phone object to remove. 
Again, it is necessary
+                to commit the Hibernate transaction.
+            </p>
+
+            <p>
+                The minimal implementation of a PrimaryKeyEncoder is also 
shown; this one is customized for
+                Phone instances, and knows how to extract primary keys (the id 
property) and convert
+                primary keys back into objects. This could easily be rolled 
out as a Tapestry IoC service.
+            </p>
+
+        </section>
+
+
+    </body>
+</document>
\ No newline at end of file

Added: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/ajaxformloop.png
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/ajaxformloop.png?rev=712816&view=auto
==============================================================================
Binary file - no diff available.

Propchange: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/ajaxformloop.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream


Reply via email to