DIY: Build an OFBiz Product List Screen

DIY Tutorial Series: Build an OFBiz Product List Screen

In this post we will create our OFBiz product list screen.  First, a simple html screen to print on screen all the products in our system.

This exercise is based on the “hwm” component we have setup in the last blog post OFBiz Tutorial – Custom Components In OFBiz: all the code we will implement will be contained in the custom component.

Here are the steps required to build the new screen:

  1. create a form definition for the list of products
  2. create a screen definition to include the form in a page
  3. create controller entries to associate the screen to a URL/address for the browser
  4. create a menu item to reach the new screen by clicking a link in a menu

All the steps we will do doesn’t require to compile/build OFBiz and can be done while OFBiz is running; in this way you will be able to test the effects of your experiments immediately.

Form widget definition for the list of products

A form widget definition is an xml representation of a list or single form.

In OFBiz, the main entity (aka database table) for storing product related information is named “Product”.

Here is the code to define a form of “list” type, together with the code to retrieve all the records from the Product entity and display them in a list based format:

Hot to build an OFBiz product list screen

The location of the file to edit

<form name="ListProducts" type="list">
    <actions>
        <entity-condition entity-name="Product">
            <order-by field-name="productId"/>
        </entity-condition>
    </actions>
    <auto-fields-entity entity-name="Product" default-field-type="display"/>
</form>

things to consider:

  • the type of this form is “list” because we want to render its content from a list in tabular format; the other main type for forms is “single” and it is used for rendering single forms (e.g. forms for data entry like “New Product”)
  • the commands under the “actions” section are executed just before the form is rendered; here we are using the “entity-condition” command to retrieve all the records from the “Product” entity sorted by “productId”
  • instead of specifying field by field all the fields to be rendered we have used the “auto-fields-entity” command; in this way all the fields from the Product entity are included as “display” (aka read only) fields

Screen widget definition for the list of products

A screen widget definition is an xml representation of a screen (page) in the application.

Here is the code to define a new screen that contains the form defined in the above step:

The location of the file to edit

The location of the file to edit

	<section>
	    <actions>
	    </actions>
	    <widgets>
	        <decorator-screen name="HwmCommonDecorator" location="component://hwm/widget/CommonScreens.xml">
	            <decorator-section name="body">
		        <include-form name="ListProducts" location="component://hwm/widget/HwmForms.xml"/>
		    </decorator-section>
		</decorator-screen>
	    </widgets>
	</section>
</screen>

Things to consider:

  • the action section of this screen is empty (we could safely remove the “actions” tags) because we have decided to run the data preparation (selection of all the records from the “Product” entity) in the form; both ways are fine: if the data retrieval logic is really tied to the form, it is a good idea to put it into the form’s action tag (reusing the same form in different screen will be just a matter of including the form in the screen definitions); if the data retrieval logic is dependent on the screen but you want to reuse the same form definition in more screens (for example one screen for different groups of products), then it is a good idea to implement it into the screen’s action tag, and then reuse the same form in all the screens; we will do this switch later in this post.
  • with the “decorator-screen” element we specify the name (“HwmCommonDecorator”) and location of a screen decorator: the screen decorator is used to decorate our screen with all the application menus, the header and footer that are shared by all the screens;
  • the screen specific content will go in the “body” section of the decorator, that is why we use the “decorator-section” element and add the screen specific content there; in this example, we have just added the form definition for the form created in the previous step
  • the path to the form widget definition is expressed in the format “component://<ofbiz component name>/<relative path to the form definition xml file>”; this format is widely used in ofbiz and it is useful because makes the system independent from the actual location of the ofbiz home folder and also enables the extension mechanism of OFBiz (we will talk about this in another post)

Controller entries – the url of our screen

Controller entries are needed to define the URL to reach the screen; for each screen you have to create two entries, a request-map and a view-map:

The location of the file to edit

The location of the file to edit

<request-map uri="ProductList">
    <security https="true" auth="true"/>
    <response name="success" type="view" value="ProductListScreen"/>
</request-map>
...
<view-map name="ProductListScreen" type="screen" page="component://hwm/widget/HwmScreens.xml#ProductList"/>

Things to consider:

  • in the controller.xml file all the request-map entries must be listed before the view-map entries
  • the request-map defines the URL of the screen for the browser; the “uri” attribute (“ProductList”) is the last part of the URL; the “security” element tells OFBiz to publish the page using the https protocol (https=”true”) and to grant access only to authenticated users (auth=”true”) (and redirect to the user login screen if a user is not already logged in); the end result is that the complete URL for the page will be: http://localhost:8080/hwm/control/ProductList
  • the view-map entry associates the “response” value defined in the request-map to the screen definition we have created in the previous step
  • there are many good reasons for decoupling the request-map to the view-map and this will be clearer when we will talk about events associated to user activities (e.g. form submissions)

Testing our work

If you have followed all the steps above you are now ready to test your work; no need to compile or restart OFBiz, just enter the following URL in your browser: https://localhost:8080/hwm/control/ProductList

You should see a screen like this: (Click on image to zoom)

OFBiz Product List

Things to consider:

  • all the fields of the Product entity have been automatically used as columns for the form list; the field names have been used to generate the column’s titles; all this happened because of the element “auto-fields-entity” we have used in the form definition
  • the framework has automatically decorated the form with pagination elements
  • all the records from the Product entity are shown, sorted by productId

A few simple experiments

Again, you can do all these changes without restarting OFBiz: just do them and reload the page after each and every change, this is a great way to explore the different options available.

The products are now sorted by productId in ascending order; if we want to sort them in descending order we just have to add the “-” symbol as a prefix of the field name in the “order-by” element of the “entity-condition”:

<entity-condition entity-name="Product">
    <order-by field-name="-productId"/>
</entity-condition>

if we want to sort by productTypeId and then productId:

<entity-condition entity-name="Product">
    <order-by field-name="productTypeId"/>
    <order-by field-name="productId"/>
</entity-condition>

If we want instead to filter all the product of type “finished good” and sort the result by productId:

<entity-condition entity-name="Product">
    <condition-expr field-name="productTypeId" value="FINISHED_GOOD"/>
    <order-by field-name="productId"/>
</entity-condition>

We can now add a label to the screen to explain that these are all the “finished products” in the system; in order to do this you will add a “label” element to the screen definition (see line 8):

<screen name="ProductList">
    <section>
        <actions>
        </actions>
        <widgets>
            <decorator-screen name="HwmCommonDecorator" location="component://hwm/widget/CommonScreens.xml">
                <decorator-section name="body">
                    <label text="Finished Products" style="h1"/>
                    <include-form name="ListProducts" location="component://hwm/widget/HwmForms.xml"/>
		</decorator-section>
	    </decorator-screen>
	</widgets>
    </section>
</screen>

Adding a menu item for the new screen

Instead of typing the URL of our screen in the browser we want to add a link to it from the top level menu of the “Hwm” application.

Here is the code to do this (new code at line 3):

hwm-menus

<menu name="MainAppBar" title="${uiLabelMap.HwmApplication}" extends="CommonAppBarMenu" extends-resource="component://common/widget/CommonMenus.xml">
    <menu-item name="main" title="${uiLabelMap.CommonMain}"><link target="main"/></menu-item>
    <menu-item name="ProductList" title="Product List"><link target="ProductList"/></menu-item>
</menu>

Things to consider:

  • the content of the “target” element must match the request-map name in the controller

Internationalization

In the last two paragraphs we have added two textual labels in English, one as a “label” element in the screen and the other as the “title” of the menu item. A better way of doing this, especially if you are interested in building internationalized applications that can be translated in many different languages, is to use the OFBiz i18n layer. In order to do this you have to add the following key in the component’s UiLabel file:

hwm-labels

<property key="HwmProductList">
    <value xml:lang="en">Product List</value>
    <value xml:lang="it">Lista Prodotti</value>
</property>

and then use the key instead of the hardcoded “Product List” string; for example for the menu item the code is:

<menu-item name="ProductList" title="${uiLabelMap. HwmProductList}"><link target="ProductList"/></menu-item>

Moving the data preparation code from the form’s to the screen’s actions tag

We have mentioned before that the data preparation code can stay in the form’s actions section or in the screen’s actions section; in the first paragraph of this post we have implemented the code in the form; we now move it to the screen’s actions section:

<screen name="ProductList">
    <section>
        <actions>
            <entity-condition entity-name="Product" list="products">
                <order-by field-name="productId"/>
            </entity-condition>
        </actions>
        <widgets>
            <decorator-screen name="HwmCommonDecorator" location="component://hwm/widget/CommonScreens.xml">
                <decorator-section name="body">
                    <label text="Finished Products" style="h1"/>
		    <include-form name="ListProducts" location="component://hwm/widget/HwmForms.xml"/>
	        </decorator-section>
	    </decorator-screen>
	</widgets>
    </section>
</screen>

The entity-condition code is exactly the same with the only difference that now we have specified the “list” attribute: this is important because it represents the name of the variable that will contain the list of products selected; this name must match the same list-name attribute in the form definition that is now:

<form name="ListProducts" type="list" list-name="products">
    <actions>
    </actions>
    <auto-fields-entity entity-name="Product" default-field-type="display"/>
</form>

The “actions” section in the form is now empty and can be safely removed.

Homework

Now that we have the data preparation code in the screen, we can more easily implement an additional screen, that reuses the same form definition to list all the products of type “raw material” (productTypeId=”RAW_MATERIAL”): the implementation of the new screen, new controller entries, menu item, ui labels is a useful exercise.

Next steps

In the next posts we will explore some of the features of form widgets (and we will enhance our product list form) and we will see how we can implement a PDF and CSV versions of the screen.

– Jacopo

 

HotWax Systems is the leading global innovator of Apache OFBiz. Stay tuned for more helpful tutorials.


DATE: Dec 18, 2009
AUTHOR: Jacopo Cappellato
OFBiz Tutorials, OFBiz Development, OFBiz Tutorial, Product List Screen, OFBiz Components, OFBiz, Jacopo Cappellato