Versions Compared

Key

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

...

Creating Practice Application (Hello World...)

Overview

This tutorial is divided in 6 Parts as:

Part 1:  In this part, you will learn how to create and load your own component (custom component) and add first screen(view) to show “This is practice application”

...

Part 6: At the final step you will ajaxify request to set a communitcation between client and server side application. After completing this application, you will become an OFBiz developer. (smile)

...

Do's and Don'ts

  1. For any additional queries and concerns you can refer Example component. You will always find the code in example component to be the latest code of OFBiz. Take reference whenever you want to see some sample code for the development of this application, this will help you in future developments as well.
    Every new feature is first added in the Example component for the references.
  2. Before starting the development of this application you must read the contents from:
    OFBiz Contributors Best PracticesCoding Conventions and Best Practices Guide
  3. Don't copy any file from other component, as the revision number for the file is also copied. Always create a new file and, if required, then copy the contents of the file." Also be conscious about the unused code as well.
  4. For searching any of the document the best place is at : OFBiz Documentation Index.
  5. Right from the beginning, reading the console log must be a habit to make troubleshooting easy and understanding the system well.
  6. You can find the source code of this application attached with this document that you are going to develop but it is preferred to just take reference from it. It can be downloaded from here: Download Source (wink)

...

  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, 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 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 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.

...

Whats next?

If you have followed all the steps and developed practice application from this tutorial then this will really help you in understanding other implementation in OFBiz. These things are basic foundation of working in OFBiz. Now you know, how you can start the development in OFBiz. Don't leave behind the extra links provided in this tutorial as they will really help you a lot in understanding the things which are given there in detail.
Here is another good reading will can be of help you a lot is available at FAQ Tips Tricks Cookbook HowTo
Now the next thing comes in the way is the business processes which are really needed to be read out understood well for understanding OOTB process flow in OFBiz and OOTB data model, so for this, books are available at : OFBiz Related Books. Understanding well the OFBiz OOTB available data model and business processes will help in building better business solutions top of it.

Now you are ready to dive in. Welcome to OFBiz world.

All the best

Thanks & Regards

Pranay Pandey