Saturday, February 5, 2011

In Context Creation of Related Objects

As I stated in my last blog post, I have been looking into solutions for ROO-207 "Allow in context creation of 1:n and 1:1 related objects". Well, I am happy to announce that I am getting there. What I have now can best be described as an early work-around. It's not a full solution, but rather a first kick at it.

The direction I'm currently going with is to change as little of the look and feel of ROO as possible. To that end, I will leave the drop down list of related items for now. I am also using Dojo for this since it is already included by ROO.

What I've done is always display the "add" icon beside the dropdown list of referenced items. Clicking on that icon launches a modal dialog box with all the fields required to create a new Object. When that modal form is submitted, the values are saved using JSON. Clicking the down arrow in the dropdown list fetches the latest Objects using JSON. There are some known issues with this solution, such as:
  1. There is no validation on the dialog form.
  2. Since it is extremely manual, it is still very error prone.
  3. If you change anything on the referenced Object, you will have to change the create page for the host Object.
  4. We fetch the latest objects every time the referenced Object list is opened. This may be an un-acceptable performance hit.
I'm publishing this work to gather the opinions of the community before going through the effort of turning this into a plugin.

A picture says a thousand words... so here are a couple thousand words.
Petclinic - Add Pet Add "Owner" from within "Add Pet" screen.

There were a few new files created

  • clinic/src/main/webapp/WEB-INF/tags/util/
    • json-util.tagx
      This file contains the JavaScript that handles the display of the dialog, the dynamic linking of the Owners select tag to the database, and the saving of the dialog form.
    • link-to-json.tagx
      This tag links the form element defined to the database though JavaScript calls to functions defined in the above file.
  • clinic/src/main/webapp/WEB-INF/tags/form
    • create-json.tagx
      This tag is based on the create.tagx in the same folder, but instead of a basic <form>, a modal dialog is created.

...and some others that just needed to be modified.

  • clinic/src/main/java/com/springsource/petclinic/domain
    • Owner.java
      Not absolutely necessary, but I added a "getName()" method so that the dropdown would display the full name of the owner.
  • clinic/src/main/webapp/WEB-INF/tags/util/
  • clinic/src/main/webapp/WEB-INF/tags/form/
    • create.tagx
      Modified since the host form was not getting submitted while the referred form was on the page.
  • clinic/src/main/webapp/WEB-INF/tags/form/fields/
    • select.tagx
      Modified to accommodate the selective inline creation of Objects.
    • textarea.tagx
      Modified to support the disabling of form binding.
  • clinic/src/main/webapp/WEB-INF/views/pets/
    • create.jspx
      Modified to include the Owner creation form.

The high level steps that are required to execute this in a clean application are:

  1. Generate the clean application.
  2. Enable JSON for the referenced objects.
  3. Copy the new and modified files.
  4. Modify the Create page for the host Objects.

Details of the changes

  1. Generate the clean application.

    roo> script --file clinic.roo
  2. Enable JSON for the referenced objects.

    roo> json add --class ~.domain.Owner
  3. Copy the new and modified files.

    Click on the file names above to download them from my server and save them into the source path indicated. (If you prefer, just download the new files and follow these instructions to modify the existing files.)

    Owner.java

    package com.springsource.petclinic.domain;

    import org.springframework.roo.addon.entity.RooEntity;
    import org.springframework.roo.addon.javabean.RooJavaBean;
    import org.springframework.roo.addon.tostring.RooToString;
    import java.util.Set;
    import com.springsource.petclinic.domain.Pet;
    import java.util.HashSet;
    import javax.persistence.OneToMany;
    import javax.persistence.CascadeType;
    import javax.persistence.Transient;

    import org.springframework.roo.addon.json.RooJson;

    @RooJavaBean
    @RooToString
    @RooEntity
    @RooJson
    public class Owner extends AbstractPerson {

        @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
        private Set<Pet> pets = new HashSet<Pet>();

        public String getName(){
         return getFirstName() + " " + getLastName();
        }

    }


    load-scripts.tagx (enable Dojo's "parseOnLoad")

    <jsp:root xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:fn="http://java.sun.com/jsp/jstl/functions" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:spring="http://www.springframework.org/tags" version="2.0">
      <jsp:output omit-xml-declaration="yes" />
      <spring:theme code="styleSheet" var="roo_css" />
      <spring:url value="/${roo_css}" var="roo_css_url" />
      <spring:url value="/resources/dojo/dojo.js" var="dojo_url" />
      <spring:url value="/resources/dijit/themes/tundra/tundra.css" var="tundra_url" />
      <spring:url value="/resources/spring/Spring.js" var="spring_url" />
      <spring:url value="/resources/spring/Spring-Dojo.js" var="spring_dojo_url" />
      <spring:url value="/resources/images/favicon.ico" var="favicon" />
      <link rel="stylesheet" type="text/css" media="screen" href="${roo_css_url}"><!-- required for FF3 and Opera --></link>
      <link rel="stylesheet" type="text/css" href="${tundra_url}"><!-- required for FF3 and Opera --></link>
      <link rel="SHORTCUT ICON" href="${favicon}" />
      <!-- Get the user local from the page context (it was set by Spring MVC's locale resolver) -->
      <c:set var="userLocale">
        <c:out value="${pageContext.response.locale}" default="en" />
      </c:set>
      <script type="text/javascript">var djConfig = {parseOnLoad: false, isDebug: false, locale: '${fn:toLowerCase(userLocale)}'};</script>

      <script src="${dojo_url}" djConfig="parseOnLoad: true, isDebug: true" type="text/javascript"><!-- required for FF3 and Opera --></script>
      <script src="${spring_url}" type="text/javascript"><!-- /required for FF3 and Opera --></script>
      <script src="${spring_dojo_url}" type="text/javascript"><!-- required for FF3 and Opera --></script>
      <script language="JavaScript" type="text/javascript">dojo.require("dojo.parser");</script>
    </jsp:root>

    create.tagx

    <jsp:root xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:fn="http://java.sun.com/jsp/jstl/functions" xmlns:util="urn:jsptagdir:/WEB-INF/tags/util" xmlns:form="http://www.springframework.org/tags/form" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:spring="http://www.springframework.org/tags" version="2.0">
      <jsp:output omit-xml-declaration="yes"/>
      <jsp:directive.attribute name="id" type="java.lang.String" required="true" description="The identifier for this tag (do not change!)"/>
      <jsp:directive.attribute name="modelAttribute" type="java.lang.String" required="true" description="The name of the model attribute for form binding"/>
      <jsp:directive.attribute name="path" type="java.lang.String" required="true" description="Specify the relative URL path (wit leading /)" />
      <jsp:directive.attribute name="label" type="java.lang.String" required="false" description="The label used for this object, will default to a message bundle if not supplied"/>
      <jsp:directive.attribute name="render" type="java.lang.Boolean" required="false" description="Indicate if the contents of this tag and all enclosed tags should be rendered (default 'true')" />
      <jsp:directive.attribute name="openPane" type="java.lang.Boolean" required="false" description="Control if the title pane is opened or closed by default (default: true)"/>
      <jsp:directive.attribute name="z" type="java.lang.String" required="false" description="Used for checking if element has been modified (to recalculate simply provide empty string value)"/>

      <c:if test="${empty render or render}">
        <c:if test="${empty label}">
          <spring:message code="label_${fn:toLowerCase(fn:substringAfter(id,'_'))}" var="label" htmlEscape="false" />
        </c:if>
        <spring:message arguments="${label}" code="entity_create" var="title_msg"/>
        <util:panel id="${id}" title="${title_msg}" openPane="${openPane}">
          <spring:url value="${path}" var="form_url"/>
          <form:form action="${fn:escapeXml(form_url)}" method="POST" modelAttribute="${modelAttribute}">
            <form:errors cssClass="errors" delimiter="&lt;p/&gt;"/>
            <jsp:doBody />
            <div class="submit" id="${fn:escapeXml(id)}_submit">
              <spring:message code="button_save" var="save_button"/>
              <script type="text/javascript">Spring.addDecoration(new Spring.ValidateAllDecoration({elementId:'proceed', event:'onclickonsubmit'}));</script>
              <input id="proceed" type="submit" value="${fn:escapeXml(save_button)}"/>
            </div>
          </form:form>
        </util:panel>
      </c:if>
    </jsp:root>

    select.tagx

    <jsp:root xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:field="urn:jsptagdir:/WEB-INF/tags/form/fields" xmlns:fn="http://java.sun.com/jsp/jstl/functions" xmlns:spring="http://www.springframework.org/tags" xmlns:form="http://www.springframework.org/tags/form" xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0">
      <jsp:output omit-xml-declaration="yes" />

      <jsp:directive.attribute name="id" type="java.lang.String" required="true" description="The identifier for this tag (do not change!)" />
      <jsp:directive.attribute name="field" type="java.lang.String" required="true" description="The field exposed from the form backing object" />
      <jsp:directive.attribute name="path" type="java.lang.String" required="true" description="The relative path to the referenced resource" />
      <jsp:directive.attribute name="items" type="java.util.Collection" required="true" description="The name of the collection displayed in the select box" />
      <jsp:directive.attribute name="label" type="java.lang.String" required="false" description="The label used for this field, will default to a message bundle if not supplied" />
      <jsp:directive.attribute name="itemValue" type="java.lang.String" required="false" description="The identifier used as value in the select box (defaults to 'id' for non enum types)" />
      <jsp:directive.attribute name="required" type="java.lang.Boolean" required="false" description="Indicates if this field is required (default false)" />
      <jsp:directive.attribute name="disabled" type="java.lang.Boolean" required="false" description="Specify if this field should be enabled" />
      <jsp:directive.attribute name="multiple" type="java.lang.Boolean" required="false" description="Specify if the select box should allow multiple selections" />
      <jsp:directive.attribute name="disableFormBinding" type="java.lang.Boolean" required="false" description="Set to true to disable Spring form binding" />
      <jsp:directive.attribute name="render" type="java.lang.Boolean" required="false" description="Indicate if the contents of this tag and all enclosed tags should be rendered (default 'true')" />
      <jsp:directive.attribute name="z" type="java.lang.String" required="false" description="Used for checking if element has been modified (to recalculate simply provide empty string value)" />
      <jsp:directive.attribute name="inlineCreate" type="java.lang.Boolean" required="false" description="Indicate if this object can be created inline (default 'false')" />

      <c:if test="${empty render or render}">

        <c:if test="${empty disabled}">
          <c:set value="false" var="disabled" />
        </c:if>

        <c:if test="${empty label}">
          <spring:message code="label_${fn:toLowerCase(fn:substringAfter(id,'_'))}" var="label" htmlEscape="false" />
        </c:if>

        <c:if test="${empty required}">
          <c:set value="false" var="required" />
        </c:if>

        <c:if test="${empty multiple}">
          <c:set value="false" var="multiple" />
        </c:if>
      
        <c:set var="sec_field">
          <spring:escapeBody javaScriptEscape="true" >${field}</spring:escapeBody>
        </c:set>

        <div id="_${fn:escapeXml(id)}_id">
          <c:choose>
            <c:when test="${not empty items or inlineCreate}">
              <label for="_${sec_field}_id">
                <c:out value="${fn:escapeXml(label)}" />
                :
              </label>
              <c:choose>
                <c:when test="${empty itemValue}">
                  <c:choose>
                    <c:when test="${disableFormBinding}">
                      <select id="_${sec_field}_id" name="${sec_field}" multiple="${multiple}">
                        <c:forEach items="${items}" var="item">
                          <option value="${item}">
                            <spring:eval expression="item" />
                          </option>
                        </c:forEach>
                      </select>
                    </c:when>
                    <c:otherwise>
                      <form:select id="_${sec_field}_id" items="${items}" path="${sec_field}" disabled="${disabled}" multiple="${multiple}" />
                      <br />
                      <form:errors cssClass="errors" id="_${sec_field}_error_id" path="${sec_field}" />
                    </c:otherwise>
                  </c:choose>
                </c:when>
                <c:otherwise>
                  <c:choose>
                    <c:when test="${disableFormBinding}">
                      <select id="_${sec_field}_id" name="${sec_field}" multiple="${multiple}">
                        <c:forEach items="${items}" var="item">
                          <option value="${item[fn:escapeXml(itemValue)]}">
                            <spring:eval expression="item" />
                          </option>
                        </c:forEach>
                      </select>
                    </c:when>
                    <c:otherwise>
                      <form:select id="_${sec_field}_id" items="${items}" path="${sec_field}" disabled="${disabled}" multiple="${multiple}" itemValue="${fn:escapeXml(itemValue)}" />
                      <br />
                      <form:errors cssClass="errors" id="_${sec_field}_error_id" path="${sec_field}" />
                    </c:otherwise>
                  </c:choose>
                </c:otherwise>
              </c:choose>
              <c:if test="${inlineCreate}">
    <spring:url value="/resources/images/add.png" var="create_img_url" />
    <spring:message arguments="${label}" code="global_menu_new" var="add_message" />
    <img onclick="showCreateDialog('${sec_field}');" alt="${fn:escapeXml(add_message)}" src="${fn:escapeXml(create_img_url)}" title="${fn:escapeXml(add_message)}" />
     </c:if>
     <br />

              <c:choose>
                <c:when test="${multiple == false}">
                  <script type="text/javascript">Spring.addDecoration(new Spring.ElementDecoration({elementId : '_${sec_field}_id', widgetType: 'dijit.form.FilteringSelect', widgetAttrs : {hasDownArrow : true}})); </script>
                </c:when>
                <!-- disabled due to http://jira.springframework.org/browse/ROO-909 <c:otherwise> <script type="text/javascript">Spring.addDecoration(new Spring.ElementDecoration({elementId : '_${field}_id', widgetType: 'dijit.form.MultiSelect', widgetAttrs : {}})); </script> </c:otherwise> -->
              </c:choose>
            </c:when>
            <c:otherwise>
              <field:reference field="${label}" id="${id}" path="${path}" required="${required}" />
            </c:otherwise>
          </c:choose>
        </div>
        <br />

      </c:if>
    </jsp:root>

    textarea.tagx

    <jsp:root xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:fn="http://java.sun.com/jsp/jstl/functions" xmlns:spring="http://www.springframework.org/tags" xmlns:form="http://www.springframework.org/tags/form" xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0">
      <jsp:output omit-xml-declaration="yes" />

      <jsp:directive.attribute name="id" type="java.lang.String" required="true" description="The identifier for this tag (do not change!)" />
      <jsp:directive.attribute name="field" type="java.lang.String" required="true" description="The field exposed from the form backing object" />
      <jsp:directive.attribute name="label" type="java.lang.String" required="false" description="The label used for this field, will default to a message bundle if not supplied" />
      <jsp:directive.attribute name="required" type="java.lang.Boolean" required="false" description="Indicates if this field is required (default false)" />
      <jsp:directive.attribute name="disabled" type="java.lang.Boolean" required="false" description="Specify if this field should be enabled" />
      <jsp:directive.attribute name="validationRegex" type="java.lang.String" required="false" description="Specify regular expression to be used for the validation of the input contents" />
      <jsp:directive.attribute name="validationMessageCode" type="java.lang.String" required="false" description="Specify the message (message property code) to be displayed if the regular expression validation fails" />
      <jsp:directive.attribute name="validationMessage" type="java.lang.String" required="false" description="Specify the message to be displayed if the regular expression validation fails" />
      <jsp:directive.attribute name="render" type="java.lang.Boolean" required="false" description="Indicate if the contents of this tag and all enclosed tags should be rendered (default 'true')" />
      <jsp:directive.attribute name="z" type="java.lang.String" required="false" description="Used for checking if element has been modified (to recalculate simply provide empty string value)" />
      <jsp:directive.attribute name="disableFormBinding" type="java.lang.Boolean" required="false" description="Set to true to disable Spring form binding" />

      <c:if test="${empty render or render}">

        <c:if test="${empty disabled}">
          <c:set value="false" var="disabled" />
        </c:if>

        <c:if test="${empty label}">
          <spring:message code="label_${fn:toLowerCase(fn:substringAfter(id,'_'))}" var="label" htmlEscape="false" />
        </c:if>

        <c:if test="${empty required}">
          <c:set value="false" var="required" />
        </c:if>
      
        <c:set var="sec_field">
          <spring:escapeBody javaScriptEscape="true" >${field}</spring:escapeBody>
        </c:set>

        <script type="text/javascript">dojo.require("dijit.form.SimpleTextarea");</script>
        <div id="_${fn:escapeXml(id)}_id">
          <label for="_${sec_field}_id">
            <c:out value="${fn:escapeXml(label)}" />
            :
          </label>
          <c:choose>
            <c:when test="${disableFormBinding}">
         <textarea id="_${sec_field}_id" name="${sec_field}">${sec_field}</textarea>
            </c:when>
            <c:otherwise>

         <form:textarea id="_${sec_field}_id" path="${sec_field}" disabled="${disabled}" />
       </c:otherwise>
     </c:choose>

          <br />
          <form:errors cssClass="errors" id="_${sec_field}_error_id" path="${sec_field}" />
          <script type="text/javascript">Spring.addDecoration(new Spring.ElementDecoration({elementId : '_${sec_field}_id', widgetType : 'dijit.form.SimpleTextarea', widgetAttrs : {disabled : ${disabled}}})); </script>
        </div>
        <br />

      </c:if>
    </jsp:root>

  4. Modify the Create page for the host Objects.

    This last step has three sub-steps. Again in our example, we want to create an Owner from within the page that we use to create a Pet.
    1. Copy the creation form from the "create Owner" page. (clinic/src/main/webapp/WEB-INF/views/owners/create.jspx)
    2. Paste it into the "create Pets" page. (clinic/src/main/webapp/WEB-INF/views/pets/create.jspx)
    3. We will then modify it.

    create.jspx (Owners - copy)

    ...
        <form:create id="fc_com_springsource_petclinic_domain_Owner" modelAttribute="owner" path="/owners" render="${empty dependencies}" z="JVL6ZvtbnTyvO3flv+5gP4Lf98o=">
            <field:input field="firstName" id="c_com_springsource_petclinic_domain_Owner_firstName" max="30" min="3" z="iFQbgU5/QXNtac+P4ovg8kEV7ek="/>
            <field:input field="lastName" id="c_com_springsource_petclinic_domain_Owner_lastName" max="30" min="3" required="true" z="njvl6BTK6olS0lu0xpz2JAljl/w="/>
            <field:textarea field="address" id="c_com_springsource_petclinic_domain_Owner_address" required="true" z="F58lrymQYAb+vI2R18H+u5MV3co="/>
            <field:input field="city" id="c_com_springsource_petclinic_domain_Owner_city" max="30" required="true" z="KeFguNGWsgzbj3W5t5xAQ67nB8w="/>
            <field:input field="telephone" id="c_com_springsource_petclinic_domain_Owner_telephone" required="true" z="UArcYWJhCMGb8fdNhd+tPR7lGZA="/>
            <field:input field="homePage" id="c_com_springsource_petclinic_domain_Owner_homePage" max="30" z="/vNZCeUDVvKka/dick16UkqxCeM="/>
            <field:input field="email" id="c_com_springsource_petclinic_domain_Owner_email" max="30" min="6" validationMessageCode="field_invalid_email" z="OBipoi4fQlmRIdM78qa1WWEIIwU="/>
            <field:datetime dateTimePattern="${owner_birthday_date_format}" field="birthDay" id="c_com_springsource_petclinic_domain_Owner_birthDay" required="true" z="hePNmv60SdPIC9BHED+b/A3wvL8="/>
            <field:simple field="pets" id="c_com_springsource_petclinic_domain_Owner_pets" messageCode="entity_reference_not_managed" messageCodeAttribute="Pet" z="mFNdxgNw45XzY+L48hMYPWM8B4E="/>
        </form:create>
    ...

    create.jspx (Pets - paste)

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <div xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:fn="http://java.sun.com/jsp/jstl/functions" xmlns:field="urn:jsptagdir:/WEB-INF/tags/form/fields" xmlns:form="urn:jsptagdir:/WEB-INF/tags/form" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:spring="http://www.springframework.org/tags" version="2.0">

        <jsp:directive.page contentType="text/html;charset=UTF-8"/>
        <jsp:output omit-xml-declaration="yes"/>
        <form:create id="fc_com_springsource_petclinic_domain_Pet" modelAttribute="pet" path="/pets" render="${empty dependencies}" z="lgvEyAlAYOudDmaPjwU0ABseTIk=">
            <field:checkbox field="sendReminders" id="c_com_springsource_petclinic_domain_Pet_sendReminders" z="uPpMX+IWb0KONpvd11fpG8x4/4Q="/>
            <field:input field="name" id="c_com_springsource_petclinic_domain_Pet_name" min="1" required="true" z="ZY+k75JeSo9RmejYZRFNIvs2aBg="/>
            <field:input field="weight" id="c_com_springsource_petclinic_domain_Pet_weight" min="0" required="true" validationMessageCode="field_invalid_number" z="cOD5zE/z7gy+RZu5kVSPuxCa+/I="/>
            <field:select field="owner" inlineCreate="true" id="c_com_springsource_petclinic_domain_Pet_owner" itemValue="id" items="${owners}" path="/owners" z="fGzswAP4XXvhPhowJKsRVve929c="/>
            <field:select field="type" id="c_com_springsource_petclinic_domain_Pet_type" items="${pettypes}" path="pettypes" required="true" z="+hDCnUp+Y+A1RlT+AjH07sgipOo="/>
        </form:create>
        <form:dependency dependencies="${dependencies}" id="d_com_springsource_petclinic_domain_Pet" render="${not empty dependencies}" z="kThDNIW+69h9nI/69ynY1WyUieo="/>
      

        <form:create id="fc_com_springsource_petclinic_domain_Owner" modelAttribute="owner" path="/owners" render="${empty dependencies}" z="JVL6ZvtbnTyvO3flv+5gP4Lf98o=">
            <field:input field="firstName" id="c_com_springsource_petclinic_domain_Owner_firstName" max="30" min="3" z="iFQbgU5/QXNtac+P4ovg8kEV7ek="/>
            <field:input field="lastName" id="c_com_springsource_petclinic_domain_Owner_lastName" max="30" min="3" required="true" z="njvl6BTK6olS0lu0xpz2JAljl/w="/>
            <field:textarea field="address" id="c_com_springsource_petclinic_domain_Owner_address" required="true" z="F58lrymQYAb+vI2R18H+u5MV3co="/>
            <field:input field="city" id="c_com_springsource_petclinic_domain_Owner_city" max="30" required="true" z="KeFguNGWsgzbj3W5t5xAQ67nB8w="/>
            <field:input field="telephone" id="c_com_springsource_petclinic_domain_Owner_telephone" required="true" z="UArcYWJhCMGb8fdNhd+tPR7lGZA="/>
            <field:input field="homePage" id="c_com_springsource_petclinic_domain_Owner_homePage" max="30" z="/vNZCeUDVvKka/dick16UkqxCeM="/>
            <field:input field="email" id="c_com_springsource_petclinic_domain_Owner_email" max="30" min="6" validationMessageCode="field_invalid_email" z="OBipoi4fQlmRIdM78qa1WWEIIwU="/>
            <field:datetime dateTimePattern="${owner_birthday_date_format}" field="birthDay" id="c_com_springsource_petclinic_domain_Owner_birthDay" required="true" z="hePNmv60SdPIC9BHED+b/A3wvL8="/>
            <field:simple field="pets" id="c_com_springsource_petclinic_domain_Owner_pets" messageCode="entity_reference_not_managed" messageCodeAttribute="Pet" z="mFNdxgNw45XzY+L48hMYPWM8B4E="/>
        </form:create>


    </div>


    create.jspx (Pets - modify)


    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <div xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:util="urn:jsptagdir:/WEB-INF/tags/util" xmlns:fn="http://java.sun.com/jsp/jstl/functions" xmlns:field="urn:jsptagdir:/WEB-INF/tags/form/fields" xmlns:form="urn:jsptagdir:/WEB-INF/tags/form" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:spring="http://www.springframework.org/tags" version="2.0">

        <util:json-util />
        <util:link-to-json field="owner" itemValue="id" path="/owners" />

        <jsp:directive.page contentType="text/html;charset=UTF-8"/>
        <jsp:output omit-xml-declaration="yes"/>
        <form:create id="fc_com_springsource_petclinic_domain_Pet" modelAttribute="pet" path="/pets" render="${empty dependencies}" z="lgvEyAlAYOudDmaPjwU0ABseTIk=">
            <field:checkbox field="sendReminders" id="c_com_springsource_petclinic_domain_Pet_sendReminders" z="uPpMX+IWb0KONpvd11fpG8x4/4Q="/>
            <field:input field="name" id="c_com_springsource_petclinic_domain_Pet_name" min="1" required="true" z="ZY+k75JeSo9RmejYZRFNIvs2aBg="/>
            <field:input field="weight" id="c_com_springsource_petclinic_domain_Pet_weight" min="0" required="true" validationMessageCode="field_invalid_number" z="cOD5zE/z7gy+RZu5kVSPuxCa+/I="/>
            <field:select field="owner" inlineCreate="true" id="c_com_springsource_petclinic_domain_Pet_owner" itemValue="id" items="${owners}" path="/owners" z="fGzswAP4XXvhPhowJKsRVve929c="/>
            <field:select field="type" id="c_com_springsource_petclinic_domain_Pet_type" items="${pettypes}" path="pettypes" required="true" z="+hDCnUp+Y+A1RlT+AjH07sgipOo="/>
        </form:create>
        <form:dependency dependencies="${dependencies}" id="d_com_springsource_petclinic_domain_Pet" render="${not empty dependencies}" z="kThDNIW+69h9nI/69ynY1WyUieo="/>
      
        <form:create-json id="fc_com_springsource_petclinic_domain_Owner" modelAttribute="owner" path="/petclinic/owners/jsonArray" render="${empty dependencies}" z="JVL6ZvtbnTyvO3flv+5gP4Lf98o=">
            <field:input field="firstName" disableFormBinding="true" id="c_com_springsource_petclinic_domain_Owner_firstName" max="30" min="3" z="iFQbgU5/QXNtac+P4ovg8kEV7ek="/>
            <field:input field="lastName" disableFormBinding="true" id="c_com_springsource_petclinic_domain_Owner_lastName" max="30" min="3" required="true" z="njvl6BTK6olS0lu0xpz2JAljl/w="/>
            <field:textarea field="address" disableFormBinding="true" id="c_com_springsource_petclinic_domain_Owner_address" required="true" z="F58lrymQYAb+vI2R18H+u5MV3co="/>
            <field:input field="city" disableFormBinding="true" id="c_com_springsource_petclinic_domain_Owner_city" max="30" required="true" z="KeFguNGWsgzbj3W5t5xAQ67nB8w="/>
            <field:input field="telephone" disableFormBinding="true" id="c_com_springsource_petclinic_domain_Owner_telephone" required="true" z="UArcYWJhCMGb8fdNhd+tPR7lGZA="/>
            <field:input field="homePage" disableFormBinding="true" id="c_com_springsource_petclinic_domain_Owner_homePage" max="30" z="/vNZCeUDVvKka/dick16UkqxCeM="/>
            <field:input field="email" disableFormBinding="true" id="c_com_springsource_petclinic_domain_Owner_email" max="30" min="6" validationMessageCode="field_invalid_email" z="OBipoi4fQlmRIdM78qa1WWEIIwU="/>
            <field:datetime dateTimePattern="MM/dd/yyyy" field="birthDay" disableFormBinding="true" id="c_com_springsource_petclinic_domain_Owner_birthDay" required="true" z="hePNmv60SdPIC9BHED+b/A3wvL8="/>
            <field:simple field="pets" id="c_com_springsource_petclinic_domain_Owner_pets" messageCode="entity_reference_not_managed" messageCodeAttribute="Pet" z="mFNdxgNw45XzY+L48hMYPWM8B4E="/>
        </form:create-json>

    </div>


3 comments:

  1. I think the pulldown should be replace by a searchable list, possibly as part of popup kind of thing so that not all related objects are retrieved on parent object load.

    Mainly because in some situations, the number of child objects may be very large and pull downs can be very inconvenient for this.

    Although in most cases you would want to immediately see the contents of the set at parent level.

    ReplyDelete
  2. mschipperheyn,
    Thanks for your feedback. I agree that there will often be times that the dropdown list will become un-manageable. I feel that this particular bug should be focused on the creation of referred objects from within the creation of their hosts. Once that functionality is implemented, the presentation of referred Objects can certainly be addressed. I don't think that there will ever be one approach that will satisfy everyones needs.

    Waldo

    ReplyDelete
  3. Wow!!. You people really talented. Good work. Go ahead!

    ReplyDelete