Thursday Jan 03, 2008

Adding a Popup Window to a NetBeans 6.0 Visual Web Page

Here is a mini-tutorial for creating a Popup window for the user to lookup values. One scenario that you might use this for is when the page visitor needs more information then can be displayed in a drop-down list.

This is a rewrite of a previous blog entry that was written for the Sun Java Studio Creator IDE. I have modified the steps so that it works for the NetBeans 6.0 IDE.

  1. Create a web application project with the Visual Web JavaServer Faces framework.

  2. Add a page named Popup.

  3. Add a Table component to the page.

  4. Drag VIR > Tables > State from the Services window and drop it on the table.

  5. Right-click the Table component and choose Table Layout from the pop-up menu.

  6. In the column for the STATE.STATEID database field, set the Component Type to Hyperlink, and click OK.

  7. Select the Hyperlink component so that its properties appear in the Properties window.

  8. Set the value for the onClick property to doSave('#{currentRow.value['STATE.STATEID']}')

    (I got the value to pass to doSave() from the Value Expression in the Table Layout dialog).

  9. Drag a Script component from the Advanced section of the Palette and drop it on the page.

  10. Click JSP in the editing toolbar to view the JavaServer Pages script.

  11. In the JSP page, change the <webuijsf:script> tag as shown below.

     
    <webuijsf:script binding="#{Popup.script1}" id="script1">
    <![CDATA[
    function doSave(val) {
     window.opener.setVal(val);
     window.close();
    }]]>
    </webuijsf:script>
    


    The Popup page is now ready for use by another page.

  12. Create a new page called Form1. Make it be the start page.

  13. Drag a Text Field component and drop it on the page. In the Properties window, make sure the id is set to textField1.

  14. Drop a Hyperlink component on the page, just above the text field, and set the text property to State Code.

  15. Set the url property to /faces/Popup.jsp.

  16. Set the onClick property to doPopup('form1:textField1_field')

    Note: Here you are passing the id of the field to fill with the selected value. Determining the id can be tricky. To determine what to use for the id, run the application, and use a tool such as Firebug to inspect the DOM.

  17. Click the ... button for the target property to open the target property editor.

  18. In the property editor, click New and set both the Display and Value to popup. Click OK and click OK again.

    Later you add script to open a window named popup, and this setting causes the Popup.jsp page to display in that window.

  19. If the target property value is still blank, select popup from the value from the combobox for that property.

  20. Drag a Script component from the Advanced section of the Palette and drop it on the page.

  21. Click JSP in the editing toolbar to view the JavaServer Pages script.

  22. In the JSP page, change the <webuijsf:script> tag as shown below.

     
    <webuijsf:script binding="#{Form1.script1}" id="script1">
    <![CDATA[
    function doPopup(destination) {
     popup = window.open("", "popup",
     "height=300,width=200,toolbar=no, menubar=no,scrollbars=yes");
     destinationElement=document.getElementById(destination);
     popup.focus();
    }
    
    function setVal(val){
     destinationElement.value=val;
    }]]></webuijsf:script>
    


  23. Run the project. Click State Code to open the popup window. Click a state code to select the code, close the popup window, and populate the text field.

Thursday Sep 06, 2007

Table Component Sample Visual Web Project for NetBeans IDE 6.0

I migrated the sample tutorial project that I created for the Sun Java Studio Creator IDE into a NetBeans IDE 6.0 web application that uses the Visual Web Java Server Faces framework. You can download this NetBeans IDE project from here. If the pages do not display in the Visual Designer (and you get an error page instead), do a clean build, then close and reopen the IDE.

Note that this project uses the JSF 1.4 versions of the Web UI components, and not the newer versions.

This sample project:

  • Gets the data from an ObjectListDataProvider
  • Has dropdown lists, checkboxes, and buttons in the table
  • Has input fields that are not associated with the underlying data provider, so the input needs to be stored separately
  • Calculates totals from the selected table rows
  • Has dynamic footer information

When you click a detail button, the button's action method uses a tableRowGroup method to get the row key for the row that the button is in. The method then uses the row key to get the value for the foodId column, which it saves in the request bean for use by the detail page.

    public String showDetailBtn_action() {
        // Find out what row was clicked
        RowKey rowKey = tableRowGroup1.getRowKey();
        // Save food id so detail page knows what food item to show
        // provide detail info for
        getRequestBean1().setFoodId(
          getSessionBean1().getFoodListDataProvider().
          getValue("foodId", rowKey).toString());
        return "detail";
    }

The checkbox column is not bound to any column in the dataprovider, but is instead bound to a page property named selected. The getter and setter use a TablePhaseListener object to manage which checkboxes are selected.

    public void setSelected(Object object) {
        RowKey rowKey = tableRowGroup1.getRowKey();
        if (rowKey != null) {
            tablePhaseListener.setSelected(rowKey, object);
        }
    }

    /\*\*
     \* Getter for selected.
     \* @return Object value for the current row's checkbox
     \*/
    public Object getSelected() {
        RowKey rowKey = tableRowGroup1.getRowKey();
        return tablePhaseListener.getSelected(rowKey);
    }

Winston explains how to do this as well as how to highlight the rows that are selected in his How to Create Muli-Row Selectable Table Component blog.

To calculate calories, the Calculate Calories button's action method calls a method that iterates over the tableRowGroup object's selectedRowKeys to accumulate the total calories for the selected rows.

    public String calculateCaloriesBtn_action() {
        getSessionBean1().setTotalCalories(getTotalCalories());
        return null;
    }

    public String getTotalCalories() {
        int total = 0;
        // Go through the list of selected rows
        Integer calories;
        Integer nbrServings;
        FoodListDataProvider foodListDP =
          getSessionBean1().getFoodListDataProvider();
        RowKey[] selectedRowKeys =
          getTableRowGroup1().getSelectedRowKeys();
        for (int i = 0; i < selectedRowKeys.length; i++) {
            String rowId = selectedRowKeys[i].getRowId();
            RowKey rowKey = foodListDP.getRowKey(rowId);
            // get serving size
            String size = (String)
              getSessionBean1().getServingSizeMap().get(rowId);
            // get calories for serving size
            calories = (Integer) foodListDP.getValue(size, rowKey);
            // get number of servings
            nbrServings = (Integer)
              getSessionBean1().getNbrServingsMap().get(rowId);
            // add to total
            total += calories.intValue() \* nbrServings.intValue();
        }
        return Integer.toString(total);
    }

The Nbr Servings text field and Serving Size drop down list are also not bound to the underlying data provider. I created Map objects to store the values for each row and bound the components to session bean properties.

    
    /\*\*
     \* Getter for property nbrServings.
     \* @return Value of nbrServings for current row
     \* defaults to 1
     \*/
    public Integer getNbrServings() {
        TableRowDataProvider rowData = 
          (TableRowDataProvider) getBean("currentRow");
        if (rowData == null) {
            return new Integer(1);
        } else {
            String rowId = 
              rowData.getTableRow().getRowId();
            Integer nbrServingsValue = 
             (Integer) this.getNbrServingsMap().get(rowId);
            if (nbrServingsValue == null) {
                return new Integer(1);
            } else {
                return  nbrServingsValue;
            }
        }
    }
    
    /\*\*
     \* Setter for nbrServings for current row
     \* @param nbrServings New value of nbrServings.
     \*/
    public void setNbrServings(Integer nbrServings) {
        TableRowDataProvider rowData = 
          (TableRowDataProvider) getBean("currentRow");
        if (rowData != null) {
            String rowId = rowData.getTableRow().getRowId();
            this.getNbrServingsMap().put(rowId, nbrServings);
        }
    }
    
    /\*\*
     \* Getter for servingSize.
     \* @return Value servingSize for current row
     \* Defaults to cup
     \*/
    public String getServingSize() {
        
        TableRowDataProvider rowData = 
         (TableRowDataProvider) getBean("currentRow");
        if (rowData == null) {
            return "cupCalories";
        } else {
            String rowId = rowData.getTableRow().getRowId();
            String servingSize = 
             (String) this.getServingSizeMap().get(rowId);
            if (servingSize == null) {
                return "cupCalories";
            } else {
                return  servingSize;
            }
        }
    }
    
    /\*\*
     \* Setter for servingSize for current row
     \* @param servingSize New value of property servingSize.
     \*/
    public void setServingSize(String servingSize) {
        TableRowDataProvider rowData = 
         (TableRowDataProvider) getBean("currentRow");
        if (rowData != null) {
            String rowId = rowData.getTableRow().getRowId();
            this.getServingSizeMap().put(rowId, servingSize);
        }
    }
    
    /\*\*
     \* Holds value of property nbrServingsMap.
     \*/
    private Map nbrServingsMap = new HashMap();
    
    /\*\*
     \* Getter for property nbrServingsMap.
     \* @return Value of property nbrServingsMap.
     \*/
    public Map getNbrServingsMap() {
        
        return this.nbrServingsMap;
    }
    
    /\*\*
     \* Setter for property nbrServingsMap.
     \* @param nbrServingsMap New value of property nbrServingsMap.
     \*/
    public void setNbrServingsMap(Map nbrServingsMap) {
        
        this.nbrServingsMap = nbrServingsMap;
    }
    
    /\*\*
     \* Holds value of property servingSizeMap.
     \*/
    private Map servingSizeMap = new HashMap();
    
    /\*\*
     \* Getter for property servingSizeMap.
     \* @return Value of property servingSizeMap.
     \*/
    public Map getServingSizeMap() {
        
        return this.servingSizeMap;
    }
    
    /\*\*
     \* Setter for property servingSizeMap.
     \* @param servingSizeMap New value of property servingSizeMap.
     \*/
    public void setServingSizeMap(Map servingSizeMap) {
        
        this.servingSizeMap = servingSizeMap;
    }
    

Monday Jul 02, 2007

Laying Out Multiple Table Components



You can use the layout components, such as the Group Panel and the Grid Panel, to easily layout and size container components, such as the Table component. In the screen shot above, the two tables on the left are in a Group Panel, and the two on the right are in a Grid Panel. I can resize or move either panel in the Visual Designer, and the contents will resize and move in accordance (they won't resize in the Visual Designer, but they will resize in the client). The trick is to set the width property of each tables to 100% so that they resize based on the size of their container.

Because the Visual Designer does not display the widths of the tables accurately, you have to right-click on the page and choose Preview in Browser to get a feel of how the tables will actually appear in the client.

Tips:

  • Set the Group Panel component's block property to true. This encloses the panel in a <div> tag.

  • You can set the Group Panel component's separator property to <br /><br /> to put spacing between the tables.

  • Set the Table component's width property to 100%. If you make changes to the table, the IDE may reset this property so keep checking to make sure it is 100%.

  • I find it best to leave the Table Column width properties blank or set them at percentage amounts, such as 10%.

Sunday Dec 17, 2006

Using the Object Array Data Provider

A forum poster recently asked for the following information:

I have a table with 5 columns, (week_no, objective, date1, date2 and add report). How do I get the date for date1( example, today's date)? How do I set the week number as auto increment by 1( example, row 1, the week_no is 1, row 2, the week_no is 2 and so on)? Lastly, how to I set the add report button to link to another JavaServer Pages file?

This scenario gives me an excellent opportunity to show how to use an Object Array Data Provider (OADP). I usually use the Object List Data Provider (OLDP), but OLDPs take a bit more work. (See the Using Hibernate tutorial for an OLDP example.) If you have a simple array of data, the OADP might be the better choice, as in this case. The following steps create a table similar to the one requested in the forum.

  1. Create a web application named ArrayTableExample.

    (If using the Visual Web Pack, be sure to create a Visual Web Application.)

  2. Create a JavaBeans object for the array. In this example, I chose to put the week number, start date, and end date in the bean. In the Projects window, right-click Source Packages > arraytableexample, choose New > Java Class, name the class WeekBean, and click Finish.
  3. Replace the class definition with the following code shown in bold.
    /\*
     \* WeekBean.java
     \*
     \*/
    
    package arraytableexample;
    
    public class WeekBean 
            extends Object implements Serializable {
        
        private int weekNumber;
        private Calendar startDate;
        private Calendar endDate;
        private int dayOfWeek; 
        
        public WeekBean(int weekNumber) {
            this.weekNumber = weekNumber;        
            Calendar workingDate = Calendar.getInstance();
            workingDate.set(java.util.Calendar.HOUR_OF_DAY, 0);
            int offset = weekNumber - 1; 
            workingDate.add(
                Calendar.DAY_OF_YEAR, 
                + (offset \* 7));
            dayOfWeek = workingDate.get(Calendar.DAY_OF_WEEK);
            startDate = (Calendar) workingDate.clone();   
            startDate.add(
            Calendar.DAY_OF_YEAR, - (dayOfWeek - Calendar.SUNDAY));
            endDate = (Calendar) workingDate.clone();
            endDate.add(
                Calendar.DAY_OF_YEAR,
                + (Calendar.SATURDAY - dayOfWeek));
        }
        
        public WeekBean() {
            this(1);
        }
            
        public int getWeekNumber() {
            return this.weekNumber;
        }
        
        public void setWeekNumber(int weekNumber) {
            this.weekNumber = weekNumber;
        }
        
        public Calendar getStartDate() {
            return this.startDate;
        }
        
        public void setStartDate(Calendar startDate) {
            this.startDate = startDate;
        }
        
        public Calendar getEndDate() {
            return endDate;
        }
        
        public void setEndDate(Calendar endDate) {
            this.endDate = endDate;
        }
    }
    
  4. Right-click in the code and choose Fix Imports. Make sure the Fully Qualified Name for Calendar is java.util.Calendar, and click OK.

  5. Close and save the file.

  6. In this example, we want the table to show the same data throughout the session, so put the array property in the session bean. In the Projects window, double-click the Session Bean node to open SessionBean1.java in the source editor.

  7. Add the following code to the bottom of the class defintion, just before the ending brace. This code also adds properties for passing the selected start and end dates to other pages.
    
        /\*\*
         \* Holds value of property weeks.
         \*/
            WeekBean[] weeks = {
                new WeekBean(1),
                new WeekBean(2),
                new WeekBean(3),
                new WeekBean(4)
            };
    
        /\*\*
         \* Getter for property weeks.
         \* @return Value of property weeks.
         \*/
        public WeekBean[] getWeeks() {
            return this.weeks;
        }
        
        /\*\*
         \* Holds value of property reportStartDate.
         \*/
        private Calendar reportStartDate;
    
        /\*\*
         \* Getter for property reportStartDate.
         \* @return Value of property reportStartDate.
         \*/
        public Calendar getReportStartDate() {
    
            return this.reportStartDate;
        }
    
        /\*\*
         \* Setter for property reportStartDate.
         \* @param reportStartDate New value of property reportStartDate.
         \*/
        public void setReportStartDate(Calendar reportStartDate) {
    
            this.reportStartDate = reportStartDate;
        }
    
        /\*\*
         \* Holds value of property reportEndDate.
         \*/
        private Calendar reportEndDate;
    
        /\*\*
         \* Getter for property reportEndDate.
         \* @return Value of property reportEndDate.
         \*/
        public Calendar getReportEndDate() {
    
            return this.reportEndDate;
        }
    
        /\*\*
         \* Setter for property reportEndDate.
         \* @param reportEndDate New value of property reportEndDate.
         \*/
        public void setReportEndDate(Calendar reportEndDate) {
    
            this.reportEndDate = reportEndDate;
        }
    
  8. Right-click in the code and choose Fix Imports. Make sure the Fully Qualified Name for Calendar is java.util.Calendar, and click OK.

  9. Close and save SessionBean1.java.

  10. View Page1 in the Visual Designer.

  11. In the Palette, expand the Data Providers section.

  12. Drag the Object Array Data Provider node and drop it on Page1.

  13. If the properties for the OADP do not appear in the Properties window, select Page1 > objectArrayDataProvider1 in the Outline window to make its properties appear.

  14. In the Properties window, change the id to weekDataProvider.

  15. Here is where it starts getting kludgy. You should be able to choose weeks from the array drop-down list, but it propably is not appearing at this point. If weeks is not in the drop-down list, choose Clean and Build Main Project from the main menu. After the build completes, close and reopen the project.

  16. In the Outline window, select Page1 > weekDataProvider.

  17. In the Properties window, select weeks (SessionBean1) from the array drop-down list.

  18. Drag a Table component from the Palette and drop it on Page1.

  19. Right-click the Table component and choose Table Layout.

  20. In the Table Layout dialog box, choose weekDataProvider from the Get Table From drop-down list.

  21. Use the Up and Down buttons to put the values in the Selected list in the following order:
    weekNumber
    startDate
    endDate
    
  22. (Optional) Set the Header Text values for the columns to Week, Start Date, and End Date.

  23. Click New to add another column.

  24. In the new column, set the Header Text to blank, select Button from the Component Type drop-down list, and set the Value Expression to Show Me.

  25. Click OK to dismiss the dialog box.

    Again, it gets kludgy. Only one row appears, which says "No items found", and there is no button. Don't worry, it will work out in the end.

  26. In the Outline window, expand table1 > tableRowGroup1 > tableColumn4, right-click button1, and choose Edit Action Event Handler.

    Page1.java opens in the source editor and scrolls to the newly added button1_action method.

  27. Add the code shown in bold to the method.
      public String button1_action() {
            getSessionBean1().setReportStartDate(
              (Calendar)getValue("#{currentRow.value['startDate']}"));
            getSessionBean1().setReportEndDate(
              (Calendar)getValue("#{currentRow.value['endDate']}"));        
            return null;
      }
    
  28. Right-click in the code and choose Fix Imports. Make sure the Fully Qualified Name for Calendar is java.util.Calendar, and click OK.

  29. Typically, you would set up page navigation to go to another page to display the report. For simplicity, click Design and drop a Static Text component on the page to display the selected start date.

  30. Right-click the Static Text component and choose Bind to Data.

  31. Click Bind to an Object, select SessionBean1 > reportStartDate, and click OK.

  32. Click Run Main Project. When the page appears, click the button in each row to verify that the action method returns the right value.

Winston has many blog entries about the dataprovider. A good place to start is his blog titled What is this Data Provider in Sun Java Studio Creator anyway?. Another good resource is Joel Brown's Weblog.

Thursday Jun 15, 2006

Table Component Sample Project

After all these months, I am finally making progress on the tutorial for the Table component. It might be a long time before I document all the steps and get the tutorial through quality assurance, editorial, and production processes. So, for those who can learn by examining code, I have decided to post the project that you build by completing the tutorial.

Here are some of the project's features:

  • Gets the data from an ObjectListDataProvider
  • Has dropdown lists, checkboxes, and buttons in the table
  • Has input fields that are not associated with the underlying data provider, so the input needs to be stored separately
  • Calculates totals from the selected table rows
  • Has dynamic footer information

Of course, everything I learned, I learned from Winston. He has posted lots of good Table component tips in his blog, so be sure to go there for advanced Table component information.

You can download the project zip from here.

Important Note: After you first open the project, build the project, then close and re-open the project. Otherwise you can get errors and the design-time mechanisms might not see the FoodListDataProvider.

Monday Mar 27, 2006

Using Checkboxes in a Table Component

Here is a one way to add a checkbox column to a table and determine which checkboxes have been checked.

  1. Add a property named selectedRows of type java.util.Set to SessionBean1.

  2. Add the following code to the init() property in SessionBean1.
    
    selectedRows = new HashSet();
    
    
  3. Add a property named selected of type boolean to SessionBean1.

  4. Change the getter and setter to the following code:
    
       /\*\*
         \* Getter for property selected
         \* @return true if checkbox in current row is selected
         \*/
        public boolean isSelected() {
            TableRowDataProvider rowData = (TableRowDataProvider) getBean("currentRow");
            if (rowData == null) {
                return false;
            } else {
                String rowId = rowData.getTableRow().getRowId();
                if (this.getSelectedRows().contains(rowId)) {
                    return true;
                } else {
                    return false;
                }
            }
        }
        
        /\*\*
         \* Setter for property selected.
         \* @param boolean; true if checkbox is selected, false if checkbox is cleared.
         \*/
        public void setSelected(boolean b) {
            TableRowDataProvider rowData = (TableRowDataProvider) getBean("currentRow");
            if (rowData != null) {
                String rowId = rowData.getTableRow().getRowId();
                if (b) {
                    this.getSelectedRows().add(rowId);
                } else {
                    this.getSelectedRows().remove(rowId);
                }
            }
        }
    
    
  5. Bind the Checkbox component's selected property to SessionBean1 > selected.

  6. Use code like the following to determine which checkboxes are selected.
    
    Iterator rows = getSessionBean1().getSelectedRows().iterator();
    while (rows.hasNext()) {
        String rowId = (String) rows.next();
        RowKey rowKey = <your table's data provider>.getRowKey(rowId);
        ... use the row key to access the data in the data provider
    }
    
    

Friday Mar 17, 2006

Iterating Through Table Data

Let's say that you want to put a footer in a column to show the column's total. To do so, you could code like the following in a property's getter method and bind the column's footer to the getter method.

        int total = 0;
        try {
            employeeDataProvider.cursorFirst();
            do {
                ... 
                total += somevalue;
                }
            } while (employeeDataProvider.cursorNext());
        } catch (Exception ex) {
            error("put your message here" +
                    ex.getMessage());
            log("put your message here: " +
                    ex.getMessage(), ex);
        }
        return total;

Sometimes, you might have some columns that are bound to the underlying data provider and some that are not. So, how do you iterate through the columns that are not bound to the data provider's fields. For those columns, you can create a hash map in the session bean that is keyed on the row id. Then you can create a getter and setter like the following and bind the column to the property (nbrServings in this example).

    public Integer getNbrServings() {
        TableRowDataProvider rowData = 
           (TableRowDataProvider) getBean("currentRow");
        if (rowData == null) {
            return new Integer(1);
        } else {
            String rowId = rowData.getTableRow().getRowId();
            Integer nbrServingsValue = 
              (Integer) this.getNbrServingsMap().get(rowId);
            if (nbrServingsValue == null) {
                return new Integer(1);
            } else {
                return  nbrServingsValue;
            }
        }
    }
    
    public void setNbrServings(Integer nbrServings) {
        TableRowDataProvider rowData = 
            (TableRowDataProvider) getBean("currentRow");
        if (rowData != null) {
            String rowId = rowData.getTableRow().getRowId();
            this.getNbrServingsMap().put(rowId, nbrServings);
        }
    }

Then add something like the following to the session bean's init method.

        nbrServingsMap = new HashMap();

You can then iterate through the has map's set of values.

Friday Mar 03, 2006

Radio Buttons in Tables

Here is a quick hack for detecting what radio button was clicked in a Table component.

Use the Table Layout dialog to add a column to the table and set its Compnent Type be Radio Button.

Add this to the page bean:

    public String getCurrentRow() {
        return tableRowGroup1.getRowKey().getRowId();
    }
   
    public void setCurrentRow(int row) {
    }
   
    private Object lastSelected="0";
   
    public Object getRBSelected() {
        String sv = (String)radioButton1.getSelectedValue();
        return sv.equals(lastSelected) ? sv : null;
    }
   
    public void setRBSelected(Object selected){
        if (selected != null) {
            lastSelected = selected;
        }
    }

In either the Outline window or the Visual Designer, select radioButton1.

In the Properties window for radioButton1, set the name property (in the Advanced section) to buttonGroup.

In the Data section for radioButton1, click the ... button for the selected property. A dialog box appears.

Select Use Binding, Click the Bind to an Object tab, select RBSelected, and click OK.

The application will now use the getRBSelected() and setRBSelected() methods to display and save user input for this component.

In the Advanced section of the Properties sheet, click the ... button for the selectedValue property.

Select Use Binding, Click the Bind to an Object tab, select currentRow, and click OK.

The application will now use the getCurrentRow() method to return the selected value for this component.

Now to find out what as been selected. In this example, the code is in a button action method:

        String aRowId = (String)RadioButton.getSelected(
                "buttonGroup");
        RowKey aRowKey = stateDataProvider.getRowKey(aRowId);
        selectedStateStaticText.setText("You Selected " +
                stateDataProvider.getValue("STATE.STATENAME",aRowKey));

If you want the selection to remain for when the user returns to the page, then you can stick the properties in a session bean. But, then you need to consider what to do if the selected row doesn't exist anymore.

Saturday Jan 14, 2006

Links in Tables

The Table tutorial will not be available for awhile, so here is a mini-tutorial on putting links in tables. It is another quick and dirty tutorial that assumes you know how to do things like bind to database tables and add bean properties.

  1. Drop a Table component on the page. Bind it to the Order > Tables > PRODUCT_TBL database table.

  2. Right-click on on the table and choose Table Layout.

  3. Have the table display the PRODUCT_NUM, PRODUCT_CODE, and DESCRIPTION.

  4. Select the PRODUCT_TBL.PRODUCT_CODE item in the Selected listbox.

  5. Choose Hyperlink from the drop-down list for the Component Type.

  6. Click OK.

  7. Double-click one of the abc text strings that appears in the column for the PRODUCT_CODE. The IDE adds a hyperlink1_action() method and opens the Java source at that method.

  8. Replace the method's body with the following code:
      return hyperlink1.getText().toString();  
    
  9. Click Design to switch to the Visual Designer.

  10. Right-click and choose Page Navigation.

  11. In the Page Navigation editor, right-click and choose New Page. Accept the default page name. Repeat until you have 6 pages in all.

  12. Drag from Page1.jsp to Page2.jsp. Type HW (name the link HW) and press Enter. Repeat for pages 3 through 7, naming the links SW, FW, BK, CB, and MS respectively (these are the product codes that the hyperlink's action method returns). You can cheat and just add pages 2 and 3. Just don't expect the other links to work.

  13. Go back to the source for Page1 and make sure the action method is still the same.

  14. Run the project and see if the links work. You might want to put values in the title property for each page convince yourself that the links are going to the right pages.

Let's say that you do not want to show the product code in the table, but you instead want the descriptions to be links to the detail pages and the detail page for a product still be different depending on the product code. Here is how you would do that.

  1. First add a String property to the request bean and name it productNum. (Right-click on Request Bean in the Projects window and choose Add > Property to open the dialog box for adding a property).

  2. In the Visual Designer for Page 1, right-click on the table and choose Table Layout.

  3. Select PRODUCT_TBL.PRODUCT_CODE and click the < button to move the product code from Selected to Available. This action removes that column from the Table component.
  4. Select PRODUCT_TBL.DESCRIPTION.

  5. Choose Hyperlink from the drop-down list for the Component Type.

  6. Click OK.

  7. Double-click one of the abc text strings that appears in the column for the PRODUCT_DESCRIPTION. The IDE adds a hyperlink action method and opens the Java source at that method. (While you are here, check to make sure the IDE removed the old hyperlink action method.)

  8. Replace the body of the method with this code:
           // Find out what row was clicked
           RowKey rowkey = tableRowGroup1.getRowKey();
           // Save product number so detail page knows what product to
           // provide detail info for
           getRequestBean1().setProductNum(
               product_tblDataProvider.getValue(
               "PRODUCT_TBL.PRODUCT_NUM", rowkey).toString());
           // Go to the detail page for that product's type
           return product_tblDataProvider.getValue(
             "PRODUCT_TBL.PRODUCT_CODE", 
              rowkey).toString();
    
  9. Right-click and choose Fix Imports. You might see a red squiggly line under the statement that calls getProductNum. This should go away after you build the application. Sometimes the synchronizer doesn't notice changes to the request bean until you compile all the files.

    Run and test.

Now, let's say that you only want people to go to detail pages for HW and SW.

Here is how to disable the links for all other product codes.

  1. Add this code to the Java source for Page1:
        private boolean linkDisabled;
        
        public boolean isLinkDisabled() {
            String productCode = product_tblDataProvider.getValue(
              "PRODUCT_TBL.PRODUCT_CODE", 
              tableRowGroup1.getRowKey()).toString();
            if (productCode.equals("HW") ||
                    productCode.equals("SW")) {
                return false;
            } else {
                return true;
            }
        }
    
  2. In the Properties window for the hyperlink, click the (...) button for the disabled property.

  3. Click Use Binding. Click the Bind to an Object tab. Select Page1 > linkDisabled.

  4. Click OK.

  5. Run and Test.

What if you only had two types of detail pages, one detail page for HW, SW, and FW and one detail page for all the other product codes. How would you do that? See if you can make it happen.

Thanks to Felix and Fredrik who motivated me to write this blog entry.

Thursday Dec 15, 2005

Paging Master Detail

I just finished upgrading the Using Databound Components to Access Databases for the final release of the product. Because this upgraded tutorial won't be published until after the final Creator 2 release comes out, I thought I would share the following piece of information that I added to the tutorial. I have seen several posts on the EA forum where people are asking how to reposition the cursor to a different table row. The answer is to call tableRowGroup1.setFirst(zero-based-index-value);.

If you use the table paging feature on a master detail page that is like the one in the tutorial (a drop-down list for the master data and a table for the detail data), you will see that when the user selects a different choice from the dropdown list, the table displays new data, but stays on the current page. For example, if the user switches to page 2 and then chooses a new item from the dropdown list, the table shows the second page of data for the new selection. To fix the problem, add the following code after the tripDataProvider.refresh() statement in the master component's value change event handler: tableRowGroup1.setFirst(0);. This ensures that the first page is always displayed when a new name is selected from the drop-down list.

A new tutorial, GoogleSearch Web Service Portlet, will be added to the EA tutorials page, hopefully today or tomorrow.

The upgrading of the Referencing Class Libraries tutorial from Creator 1 to Creator 2 was low on our priority list. However, several people sent a request for this tutorial to the CreatorDocsFeedback@Sun.Com alias. So, we have upgraded this tutorial and it is going through the engineering review process. Your input matters to us, so please continue to submit tutorial suggestions.

About

divas

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today