Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Info
titleSource Code!

OFBiz
Download Apache OFBiz™
OFBiz Source Repository and Access

Tutorial
The source code for of the Practice Application demonstrated in this tutorial can be downloaded from here: Download Source Code .

Framework Introduction Videos
These are old but still worth watching if you want. In parallel with the development of this application,you can view OFBiz videos, which are available Find these at Framework Introduction Videos and Diagrams,.

Table of Contents

Creating Practice Application (Hello World...)

...

  1. For any additional queries and concerns you can refer to the Example component. You will always find the code in the example component reflects the latest version of OFBiz. Refer to it whenever you want to see some sample code for the development of this application. This will help you in future development activities as well.
    When each new feature is added, it is added in the Example component as a reference.
  2. Before starting the development of this application you must read the :
    1. OFBiz Contributors Best Practices ,  
    2. Coding Conventions and
    3. Best Practices Guide
  3. Don't copy any files from other components, as the revision number for the file is also copied. Always create a new file and, if required,  copy copy and paste the contents of the original file. Also be careful to remove any unused code as well.
  4. For searching for any documents the best place to start is : OFBiz Documentation Index.
  5. Right from the beginning, reading the console log must be a habit to make troubleshooting easy. It also gives an understanding of the system's internal processing steps.

...

  1. Create the sub-directory (folder) in hot-deploy/ and name it "practice" (hot-deploy/practice). The directory name should match the name of the component.
    Note : Remember that all development for this componentis component should be done in this folder only. 
  2. Create the ofbiz-component.xml file on path hot-deploy/practice and place the following contents in it. You can check the corresponding file in any other OfBiz OOTB OFBiz component to see how it is used in that component.:

    Code Block
    <?xml version="1.0" encoding="UTF-8"?>
    <ofbiz-component name="practice"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/ofbiz-component.xsd">
          <resource-loader 	name="main" type="component"/>
        <webapp name="practice"
           title="Practice"
           server="default-server"
           base-permission="OFBTOOLS"
           location="webapp/practice"
           mount-point="/practice"
           app-bar-display="false"/>
    </ofbiz-component>
    

...

AttributeDescriptionRequired
namethe name of our web applicationtrue
titlethe title of the application which will be shown in the top navigationtrue
serverthe server to usetrue
base-permissionthe permissions required to use this component. This example requires that the user should have the OFBTOOLS permission Since the 'admin' user has this permission we do not have to create any new users in order to test this component,.true
locationthe default base directory for the servertrue
mount-point the URL used to access this resource. in this case it would be localhost:8080/practice.true
app-bar-displaytrue if the component should show up in the main application tabs that are part of the common OFBiz decoratortrue

...

  1. Create a "webapp" directory in the practice component (hot-deploy/practice/webapp).
    This directory contains all the webapp related files for the component we are creating.
  2. Since "practice" is the name of the webapp which you are going to develop, create a hot-deploy/practice/webapp/practice folder. A component can consist of multiple webapps  . For example,. E.g. the "marketing" component has two webapps "marketing" and "sfa".
  3. Create the hot-deploy/practice/webapp/practice/WEB-INF directory.
    An OFBiz web application requires two configuration files, a controller.xml and a web.xml. The controller.xml tells OFBiz what to do with various requests from visitors: what actions to take and what pages to render. web.xml tells OFBiz what resources (database and business logic access) are available for this web application and how to handle web-related issues, such as welcome pages, redirects, and error pages.
  4. Create a file named "web.xml"(web.xml follows j2ee webapp specs). Contents of this file can be copied from any of the existing component e.g. /framework/example component. The Important values to change are the <display-name>, the localDispatcherName, the mainDecoratorLocation and the webSiteId.

    Code Block
    <context-param>
        <param-name>webSiteId</param-name>
        <param-value>PRACTICE</param-value>
        <description>A unique ID used to look up the WebSite entity to get information about catalogs, etc.</description>
    </context-param>
    <context-param>
         <param-name>localDispatcherName</param-name>
         <param-value>practice</param-value>
         <description>A unique name used to identify/recognize the local dispatcher for the Service Engine</description>
    </context-param>
    <context-param>
         <param-name>mainDecoratorLocation</param-name>
         <param-value>component://practice/widget/PracticeScreens.xml</param-value>
         <!-- change the path to the following if the above doesn't work for you -->
         <!-- <param-value>component://practice/webapp/practice/widget/PracticeScreens.xml</param-value> -->
         <description>The location of the main-decorator screen to use for this webapp; referred to as a context variable in screen def XML files.</description>
    </context-param> 
    
    1. For now just put websiteId as "PRACTICE". This will be explaned later in this tutorial.
    2. For now put the value: "component://practice/widget/CommonScreens.xml" in for the mainDecoratorLocation. You will see why in a while. This location is used in pointing to the main decorator location in screens like

      Code Block
      ${parameters.mainDecoratorLocation}
      

      This increases the Independence from changes in many places when we need to change the main decorator location. We will just need to change the location in one spot and it will work for all the screens where it has been used. Another advantage of doing this in screens is resuability of existing screens which we can be used in multiple components where the same pattern is used to show the mainDecoratorLocation. Remember this when you add decorators in your screens.

    3. Create a file named "controller.xml" (used by ofbiz webapp controller)  This file will be small and simple at first but will grow as we add functionality later on. For now insert the following code:

      Code Block
      <?xml version="1.0" encoding="UTF-8"?>
      <site-conf xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/site-conf.xsd">
             <include location="component://common/webcommon/WEB-INF/common-controller.xml"/>
             <description>Practice Component Site Configuration File</description>
             <owner>Copyright 2001-2009 The Apache Software Foundation</owner>
             <!-- Request Mappings -->
             <request-map uri="main">
                 <security https="false" auth="false"/>
                 <response name="success" type="view" value="main"/>
             </request-map>
             <!-- end of request mappings -->
             <!-- View Mappings -->
             <view-map name="main" type="screen" page="component://practice/widget/PracticeScreens.xml#main"/>
             <!-- change the path to the following if the above doesn't work for you -->
             <!-- <view-map name="main" type="screen" page="component://practice/webapp/practice/widget/PracticeScreens.xml#main"/> -->
      
             <!-- end of view mappings -->
      </site-conf>
      

      Creating the User Interface

...

  1. For this create directory by name "config" in your component directory i.e. "practice".
    Note: -Here remember to create an entry for the config directory in your ofbiz-component.xml file.
    which will be:

    Code Block
    <classpath type="dir" location="config"/>
    

    That means you have to place the config directory on the classpath to access configuration files.

  2. Now create a file by name PracticeUiLabels.xml and create some of the ui labels for practice applicaton. (take reference from ExampleUiLabels.xml). Here remember one thing whenever you make a change in UiLabels then you have to restart the server for having the changes in effect. At first create only 2 ui labels like

    Code Block
    <property key="PracticeApplication">
        <value xml:lang="en">This is first 	practice</value>
    </property>
    <property key="PracticeCompanyName">
        <value xml:lang="en">OFBiz: Practice</value>
    </property>
    
  3. Include this UI Label resource in your main decorator screen which you created earlier and use these one or two ui UI labels which you are having now.
  4. Use those 2 UI labels at appropriate places.
    Note: Always search first for any existing Ui UI label in ofbiz OFBiz and if you don't find it there then only create the new one.
    Now run the application and see the output screen as bellow from :
    Output Screen:

...

Events can be written in Java and minilang both. Now the next development which you are going to do will be writting writing these events.
Events are used for the validation and conversion using Simple Map Processor. The Simple Map Processor Mini-Language performs two primary tasks: validation and conversion. It does this in a context of moving values from one Map to another. The input map will commonly contain Strings, but can contain other object types like Integer, Long, Float, Double, java.sql.Date, Time, and Timestamp.
Before moving any further an important link to go through is : Mini-Language Guide (Version 2 - Deprecated), Old link(http://ofbiz.apache.org/docs/minilang.html). For making an understanding with it implementation will be done by performing following steps:

  1. For this create another tab in your practice application menu bar for this by Name "Events".
  2. Now create another menu with two menu item in PracticeMenus.xml file by name "EventMenu". This menu will be having 2 menu Item one will be by name "EventMinilang" and  another by name "EventJava". One will be used to show the form which we will be calling an event which will be in minilang and other will be used to call java event.
  3. Simply show form on the request of both which will be for creating a new person. Both the forms will be different for calling different events as target in them.

    Code Block
    <menu name="EventMenu" default-menu-item-name="eventMinilang" default-selected-style="selected"
             type="simple" menu-container-style="button-bar button-style-1" selected-menuitem-context-field-name="headerItem">
          <menu-item name="eventMinilang" title="Create Person --- Event MiniLang">
               <link target="createPracticePersonEventM"/>
          </menu-item>
          <menu-item name="eventJava" title="Create Person --- Event Java">
               <link target="createPracticePersonEventJ"/>
          </menu-item>   
    </menu>
    
  4. Show labels in screens above the form like "New Person - Simple Event"  and  "New Person - Java Event" so that it will be easy to identify the purpose of that form.
  5. Now set event in the target of the forms and create request mappings in controller for the event.
    Here important thing to note is in case of simple event controller entry will be like :

    Code Block
    <request-map uri="createPracticePersonSimpleEvent">
        <security https="true" auth="true"/>
        <event type="simple" path="component://practice/script/org/hotwax/practice/PracticeEvents.xml" invoke="createPracticePersonSimpleEvent"/>
        <response name="success" type="view" value="CreatePracPersonSimpleEvent"/>
        <response name="error" type="view" value="CreatePracPersonSimpleEvent"/>
    </request-map>
    

    Here the path is the path of the file where the event is written. it will be practice/script/org/hotwax/practice.
    and for java event controller entry will be like:

    Code Block
    <request-map uri="createPracticePersonJavaEvent">
        <security https="true" auth="true"/>
        <event type="java" path="org.hotwax.practice.PracticeEvents" invoke="createPracticePersonJavaEvent"/>
        <response name="success" type="view" value="CreatePracPersonJavaEvent"/>
        <response name="error" type="view" value="CreatePracPersonJavaEvent"/>
    </request-map>
    

    Here the path is the classpath in which this event is defined. 
    The file name will be PracticeEvents.java and will be created at  practice/src/org/hotwax/practice.

...

  1. Now in the script/org/hotwax/practice/ create one file by name PracticeEvents.xml.
  2. Write the event in PracticeEvents.xml file by name createPracticePersonSimpleEvent.(For reference you can go through the event "createUser" from UserEvents.xml from party component)
    The event which you will be writing should be the simple one as you just have to process 5 fields coming from the form which are salutation, firstName, middleName, lastName, suffix. and then you have to call the createPracticePerson service.
    For processing the field you will be using simple map processor as you have read earlier. 
    Follow these steps for writing the event:
    1. Process fields coming from the form like: 

      Code Block
      <call-map-processor in-map-name="parameters" out-map-name="createPersonContext">
          <simple-map-processor name="createPersonMap">
              <process field="firstName">
                  <copy/>
                  <not-empty>
                      <fail-property property="PracticeFirstNameMissingError" resource="PracticeUiLabels"/>
                  </not-empty>&nbsp;&nbsp;&nbsp;
              </process>
          </simple-map-processor>
      </call-map-processor>
      <check-errors/>
      
    2. Create some Ui labels for showing them in fail-property like PracticeFirstNameMissingError.
    3. Now call service createPracticePerson service by passing out map which is obtained after processing fields as a an in map to the service.
      OutPut Screen :

...

Here the java event which you will be writing will be fairly simple. For reference, you can check any of the *Events.java filefiles.

  1. The contents will be :

    Code Block
    public static String createPracticePersonJavaEvent(HttpServletRequest request, HttpServletResponse response){
        LocalDispatcher dispatcher = (LocalDispatcher) request.getAttribute("dispatcher");
        GenericDelegator delegator = (GenericDelegator) request.getAttribute("delegator");
    }
    
  2. Now you have to process the fields comming coming from the form like

    Code Block
    String salutation = (String) request.getParameter("salutation");
    String firstName = (String) request.getParameter("firstName");
    
  3. Now prepare a map for the values which you have to pass to the service which you will call "createPracticePerson" . Like

    Code Block
    Map createPersonCtx = UtilMisc.toMap("salutation", salutation, "firstName", firstName);
    
  4. Then at the end just call the service "createPracticePerson" like

    Code Block
    try{
        Map person = dispatcher.runSync("createPracticePerson", createPersonCtx);
     }catch (GenericServiceException e){
         Debug.logError(e.toString(), module);
         return "error";
     }
    return "success";
    

    After writting event in Java don't forget to compile it by running "ant" command. At this moment you will need to add build.xml file to your component directory i.e. at hot-deploy/practice/ For the content of build.xml file you can refer "example" component.
    Here in build.xml file ensure one thing you are having follwing entry:

    Code Block
    <target name="classpath">
        <path id="local.class.path">
            <fileset dir="../../framework/base/lib/j2eespecs" includes="*.jar"/>
        </path>
    </target>
    

    This will needed for the classes like

    Code Block
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    

    So create a file by name build.xml and then compile it. It will create a build directory in your component directory which will be containing all *.jar and class files after compilation. For the content of build.xml file you can refere example component. 
    For running the simple event don't forget to make an entry for <classpath type="dir" location="script"/> in ofbiz-component.xml file.
    For running the java event make an entry <classpath type="jar" location="build/lib/*"/> in ofbiz-component.xml file.

...

  1. For this you have to write another service by name "createPartyRoleVisitor",  which will be setting the role for the party which will be created by "createPracticePerson" service.
    The service "createPartyRoleVisitor" will be triggered by the seca rule which you will define for service "createPracticePerson".
    In the new service involved entity will by "PartyRole". In "createPartyRoleVisitor" just call service "createPartyRole" which is already implemented.
  2. Now you have to create a file by name "secas.xml" in "servicedef" directory. Seca definition will come here. (Take reference from secas.xml of "party" component). This will be

    Code Block
    <eca service="createPracticePerson" event="commit">
        <condition field-name="partyId" operator="is-not-empty"/>
        <action service="createPartyRoleVisitor" mode="sync"/>
    </eca>
    
  3. Do an entry in ofbiz-component.xml file for this seca definition to to be loaded. It will be :
    <service-resource type="eca" loader="main" location="servicedef/secas.xml"/>
    Don't forget to restart the server after doing this entry.
    Now run the service through form and check the records in PartyRole entity. You will find a role is set for the party created because synchrounously synchronously you have triggered another service by seca rule for setting up the role for the party created.

EECA

  1. For this, you have to write another service by name "createPartyRoleCustomer",  which will be setting the role for the party which will be created means when a record for the entity "Party" will be created this service will be triggered for setting a role customer for that party. The service "createPartyRoleCustomer" will be similar to "createPartyRoleVisitor".
  2. Now you have to create a file by name "eecas.xml" in "entitydef" directory, which will be in your component directory "practice". Eeca definition will come here. (Take reference from eecas.xml of "accounting" component). This will be :

    Code Block
    <!-- To create party role whenever a party is created -->
    <eca entity="Party" operation="create" event="return">
        <condition field-name="partyId" operator="is-not-empty"/>
        <action service="createPartyRoleCustomer" mode="sync"/>
    </eca>
    
  3. Do an entry in ofbiz-component.xml file for this seca definition to to be loaded. It will be :

    Code Block
    <entity-resource type="eca" reader-name="main" loader="main" location="entitydef/eecas.xml"/>
    

    Don't forget to restart the server after doing this entry.
    Now run the service through form and check the records in PartyRole entity. You will find a role is set for the party created because synchrounously you have triggered a service by eeca rule for setting up the role for the party created.
    The main difference here is that you are triggering a service when an operation is performed on the entity. In our case it is "create".
    Note Here you have created a saparate menu to understand the concept separately. As you written seca for the service "createPracticePerson", so where ever in your practice application you will be calling this service that seca will trigger "createPartyRoleVisitor" and on the other hand when a party will be created "createPartyRoleCustomer" will be triggered.
    Output Screen :

     

...

  1. Create a new subdirectory by name entitydef in hot-deploy/practice/.
  2. Create new file by name  entitymodel.xml. This file will contain the defintions of entities which you want to define.
  3. For loading the defintion you need to do an entry in your ofbiz-component.xml file like:

    Code Block
    languagexml
    <entity-resource type="model" reader-name="main" loader="main" location="entitydef/entitymodel.xml"/>
    

    That implies that when ever you do a change you need to restart the server to have those changes in effect.
    At this place, an important reading is can be found at http://ofbiz.apache.org/docs/entity.html.
    You will rarely find this way to define new entity because you are already having entities there in OFBiz already defined which will be useful for the conduction of your business process. Though you may feel at some place to add more fields to an existing entity so how can you do that? The next  step will show you the way how you can extend an entity for your customized needs.
    Earlier we used to have one more file in the same directory by name entitygroup.xml which not needed any more because code is checked in to the trunk for this.

Extending an Existing OOTB Entity

Yes, you can extend an existing entity for adding more fields to for your custom needs. This can be done in following way:

  1. For extending an entity you can do in this manner in the entitydef/entitymodel.xml file of your custom application.

    Code Block
    languagexml
    <extend-entity entity-name="">
        <field name="" type=""/>
    </extend-entity>
    

    As an example of this, you can refer entitymodel.xml file from party component.
    This is the simplest form it can be more complex. This will add up one more field to the entity you already have. Now it depends which field you want for your custom needs. Here you can also defined relation of this field with other entities you want. But before doing this you should search extesively may be you will be adding a field for a purpose and there is already a field which will serve the purpose, so be concisous about this. Also go for a extensive study of data model then do this.
    For entity engine configuration dont don't forget to read : go through Entity Engine Configuration Guide

...

  1. Make entry of /js in allowedPaths of web.xml. So now allowed paths parameter will look like given below:
    1. This will allow .js files which are under /js folder to load.
    2. Step -7 will make you understand more, why we are doing this entry here.

      Code Block
      <init-param>
          <param-name>allowedPaths</param-name>
          <param-value>/control:/select:/index.html:/index.jsp:/default.html:/default.jsp:/images:/includes/maincss.css:/js</param-value>
      </init-param>
      

      *Note: * Here you must not miss that this will require a server restart.

  2. Include validation.js and prototype.js in main-decorator in practice/widget/CommonScreens.xml. For this you have to write below given code in <actions> block of main-decorator.
    1. We are including these library files in main-decorator screen, because all other screens uses main-decorator and thus both the libraries will be available in other screens as well.

      Code Block
      <set field="layoutSettings.javaScripts[+0]" value="/images/prototypejs/validation.js" global="true"/>
      <set field="layoutSettings.javaScripts[]" value="/images/prototypejs/prototype.js" global="true"/>
      

      validation.js and prototype.js are located at framework/images/webapp/images/prototypejs/

  3. Add another menu item to application menu bar by name "Ajax". Below given is the controller entry:

    Code Block
    <!-- Request Mapping -->
    <request-map uri="Ajax">
        <security https="true" auth="true"/>
        <response name="success" type="view" value="PersonFormByAjax"/>
    </request-map>
    
    <!-- View Mapping -->
    <view-map name="PersonFormByAjax" type="screen" page="component://practice/widget/PracticeScreens.xml#PersonFormByAjax"/>
    
  4. Create new screen called "PersonFormByAjax" in PracticeScreens.xml. Example code is given below:
    1. PracticeApp.js is the custom js file where we will be writing our custom js code for ajaxifying our request.
    2. person.ftl is the same file we created above.
    3. CreatePerson.ftl is a new file which you need to create now. This file contains form for creating new person, which is same as we created in step-1 of Part-3 under "Writing CRUD operations for Person entity" section. Only difference is that this form is written in freemarker.

      Code Block
      <screen name="PersonFormByAjax">
          <section>
              <actions>
                  <set field="headerItem" value="ajax"/>
                  <set field="titleProperty" value="PageTitlePracticePersonForm"/>
                  <property-map resource="PartyUiLabels" map-name="uiLabelMap" global="true"/>
                  <set field="layoutSettings.javaScripts[]" value="/practice/js/PracticeApp.js" global="true"/>
                  <entity-condition entity-name="Person" list="persons"/>
              </actions>
              <widgets>
                  <decorator-screen name="CommonPracticeDecorator" location="${parameters.mainDecoratorLocation}">
                      <decorator-section name="body">
                          <platform-specific>
                              <html>
                                  <html-template location="component://practice/webapp/practice/person.ftl"/>
                                  <html-template location="component://practice/webapp/practice/CreatePerson.ftl"/>
                              </html>
                          </platform-specific>
                      </decorator-section>
                  </decorator-screen>
              </widgets>
          </section>
      </screen>
      
  5. Create new file CreatePerson.ftl explained above in practice/webapp/practice/ and place below given code:
    1. Also, notice ids used in this ftl file.
    2. We will be using these ids in our js file.

      Code Block
      <h2>${uiLabelMap.PartyCreateNewPerson}</h2>
      <div id="createPersonError" style="display:none"></div>
      <form method="post" id="createPersonForm" action="<@ofbizUrl>createPracticePersonByAjax</@ofbizUrl>">
        <fieldset>
          <div>
            <label>${uiLabelMap.FormFieldTitle_salutation}</label>
            <input type="text" name="salutation" value=""/>
          </div>
          <div>
            <label>${uiLabelMap.PartyFirstName}*</label>
            <input type="text" name="firstName"  value=""/>
          </div>
          <div>
            <label>${uiLabelMap.PartyMiddleName}</label>
            <input type="text" name="middleName" value=""/>
          </div>
          <div>
            <label>${uiLabelMap.PartyLastName}*</label>
            <input type="text" name="lastName" class="required" value=""/>
          </div>
          <div>
            <label>${uiLabelMap.PartySuffix}</label>
            <input type="text" name="suffix" value=""/>
          </div>
          <div>
            <a id="createPerson" href="javascript:void(0);" class="buttontext">${uiLabelMap.CommonCreate}</a>
          </div>
        </fieldset>
      </form>
      
    3. Click on "Ajax" menu to observe the PersonFormByAjax screen.
  6. Add new div in person.ftl file. Now person.ftl will look like:
    1. Here again, div's id will be used in PracticeApp.js file

      Code Block
      <#if persons?has_content>
        <div id="personList">
          <h2>Some of the people who visited our site are:</h2>
          <br>
          <ul>
            <#list persons as person>
              <li>${person.firstName!} ${person.lastName!}</li>
            </#list>
          </ul>
        </div>
      </#if>
      
  7. Now create PracticeApp.js in practice/webapp/practice/js/ and place the below given code :
    1. Here on first line, Event.observe(element, eventName, handler), registers an event handler on a DOM element.
      1. Argument 1: The DOM element you want to observe; as always in Prototype, this can be either an actual DOM reference , or the ID string for the element.
      2. Argument 2: The standardized event name, as per the DOM level supported by your browser. This can be as simple as 'click'.
      3. Argument 3: The handler function. This can be an anonymous function you create on-the-fly, a vanilla function.
    2. So here on window load, an on-the-fly function is called. where form validations and request calling is done.
    3. Important thing to notice is why we write other observation code on window load event, and answer is here we keep restriction, that on window load, all the elements of the form will get activated and then we put observation on form's elements.
    4. In CreatePerson.ftl you see that class="required" are used on forms's input element, You then activate validation by passing the form or form's id attribute as done in second line. More on this can be learned from learn validation
    5. On third line, observer is on "createPerson" which is id of anchor tag (button) in CreatePerson.ftl,
    6. so that when end user clicks "create button" , the instance method, validate(), will return true or false. This will activate client side validation.
    7. And then the createPerson function is called which is out of the scope of window load observer.
    8. In request variable, createPersonForm's action is stored. $('createPersonForm') is again a id of form in CreatePerson.ftl.
    9. new Ajax.Request(url) : Initiates and processes an AJAX request.
    10. The only proper way to create a requester is through the new operator. As soon as the object is created, it initiates the request, then goes on processing it throughout its life-cyle.
    11. Request life cycle:
      1. Created
      2. Initialized
      3. Request sent
      4. Response being received (can occur many times, as packets come in)
      5. Response received, request complete
    12. So here createPracticePersonByAjax request will be called from controller.xml, which will call createPracticePerson service and do needful entries.
    13. Form's elements are serialized and passed as a parameter in ajax request. This is represented in the last line of createPerson function.
    14. Now if response is successful and server has not returned an error, "new Ajax.Updater($('personList'), 'UpdatedPersonList'" will be executed.
    15. Ajax updater, performs an AJAX request and updates a container's contents based on the response text. To get more on this please read : ajax updater
    16. So "personList" is the id of div in person.ftl, which will be replaced by response of UpdatedPersonList request.

      Code Block
      Event.observe(window, 'load', function() {
          var validateForm = new Validation('createPersonForm', {immediate: true, onSubmit: false});
          Event.observe('createPerson', 'click', function() {
             if (validateForm.validate()) {
                 createPerson();
             }
          });
      });
      
      function createPerson() {
          var request = $('createPersonForm').action;
          new Ajax.Request(request, {
              asynchronous: true,
              onComplete: function(transport) {
                  var data = transport.responseText.evalJSON(true);
                  var serverError = getServerError(data);
                  if (serverError != "") {
                      Effect.Appear('createPersonError', {duration: 0.0});
                      $('createPersonError').update(serverError);
                  } else {
                      Effect.Fade('createPersonError', {duration: 0.0});
                      new Ajax.Updater($('personList'), 'UpdatedPersonList', {evalScripts: true});
                  }
              }, parameters: $('createPersonForm').serialize(), requestHeaders: {Accept: 'application/json'}
          });
      }
      getServerError = function (data) {
          var serverErrorHash = [];
          var serverError = "";
          if (data._ERROR_MESSAGE_LIST_ != undefined) {
              serverErrorHash = data._ERROR_MESSAGE_LIST_;
      
              serverErrorHash.each(function(error) {
                  if (error.message != undefined) {
                      serverError += error.message;
                  }
              });
              if (serverError == "") {
                  serverError = serverErrorHash;
              }
          }
          if (data._ERROR_MESSAGE_ != undefined) {
              serverError += data._ERROR_MESSAGE_;
          }
          return serverError;
      };
      
  8. Now do required controller.xml entries :
    1. Here you may see that after service invocation request is chained and and is redirected to json request.
    2. json request is in common-controller.xml which invokes common json reponse events and send back json reponses.

      Code Block
      <request-map uri="createPracticePersonByAjax">
          <security https="true" auth="true"/>
          <event type="service" invoke="createPracticePerson"/>
          <response name="success" type="request" value="json"/>
          <response name="error" type="request" value="json"/>
      </request-map>
      <request-map uri="UpdatedPersonList">
          <security https="true" auth="true"/>
          <response name="success" type="view" value="UpdatedPersonList"/>
      </request-map>
      <!--View Mappings -->
      <view-map name="UpdatedPersonList" type="screen" page="component://practice/widget/PracticeScreens.xml#UpdatedPersonList"/>
      
  9. Finally create UpdatedPersonList screen in practice/widget/PracticeScreens.xml
    1. This is same as Person Screen
    2. Now this screen will be shown by Ajax updater.

      Code Block
      <screen name="UpdatedPersonList">
          <section>
              <actions>
                  <script location="component://practice/webapp/practice/WEB-INF/actions/person.groovy"/>
              </actions>
              <widgets>
                  <platform-specific>
                      <html>
                          <html-template location="component://practice/webapp/practice/person.ftl"/>
                      </html>
                  </platform-specific>
              </widgets>
          </section>
      </screen>
      
  10. Now submit the form and and run your ajax request.
Note
titleImportant
  • One important thing to remember is "id" used in form should always be unique. And if you use same id on different elements then prototype may get confused and your javascript will be blocked. these can well observed using firbug.
  • Also installation of firebug is suggested from get firebug, for debugging javascript in Mozilla.

...