Sunday 28 February 2010

Displaying lookups from other tables in ListGrid

Here's a problem in smartGWT: You have a ListGrid that displays data from a table table. One or more columns are integer IDs that refer to other tables. Those tables have meaningful text in them (e.g. code-description tables or perhaps account or client names).

Let's assume that you are displaying client data. Rather than displaying the internal row ID for the client, you want to display the client name using the foreign key ID on your ListGrid data to look up the name in the client table.

This is easy in smartGWT. You need to use a facility called "OptionDataSource". The smartGWT documentation says that you need to set OptionDataSource on the column in question.

Now the smartGWT documentation leads you up the gardent path a bit with using this facility. Put bluntly, their method doesn't work when you have a ListGrid that is based entirely on a datasource. This is because you cannot use ListGrid.getField(...) to get the column in order to set OptionDataSource because, until it's displayed, the ListGrid is empty. So you continually get an error trying to set attributes on a null!

To work around this problem. smartGWT has ListGrid..setUseAllDataSourceFields. If you set true for this, this means that you can now create one or more ListGridField types, call setOptionDataSource on these new objects as well as setValueField and setDisplayField and then, crucially, at the end of all this, you call ListGrid.setFields to add these to the ListGrid.

Here's the part that is very unclear in the smartGWT documentation: You need to use setName to name your new objects to the same name as the columns in the ListGrid's datasource that you want to set the OptionDataSource values for. What happens is that smartGWT will then use your new objects to overwrite the objects in the datasource, i.e. you are replacing those columns with your own versions of those columns.

The part that is really not clear in any documentation or forum entries is that this is how you are establishing the mapping between the column in the ListGrid datasource that has the ID (in our example, the client ID) that you wish to display the meaningful text for from the alternative table (OptionsDataSource). In our example this is the client's name.

Specifically:
   ListGridField.setName: Set to the ListGrid datasource column that you wish to implement the lookup on.
   ListGridField.setOptionDataSource: Set the alternative datasource that contains the lookup data (must have the code and the displayed value)
  ListGridField.setValueField: Set the column in the alternative datasource that has the code values that match those in the ListGrid column that you specified in setName above (in our example, this is the client id column of the lookup table). After you have set this as well as setName above, smartGWT now has both column names that are used to lookup the data.
  ListGridField.setDisplayField: This tells smartGWT what column to use to display instead of the ID (in our example, this is the client name column of the lookup table).

Here is some sample code that implements a lookup of Group Name based on a group_id in the ListGrid datasource. The ListGrid object is recipientGrid and the lookup datasource is GroupHeaderDS.

        ListGridField groupID=new ListGridField();
        groupID.setOptionDataSource(GroupHeaderDS.getInstance());
        groupID.setValueField("group_id");
        groupID.setDisplayField("group_name");
        groupID.setName("group_id");
        groupID.setTitle("Group Name");
        groupID.setAutoFetchDisplayMap(true);
        recipientGrid.setFields(groupID);
        recipientGrid.setAutoFetchDisplayMap(true);

Thursday 18 February 2010

smartGWT - how to implement a date and time picker/chooser

SmartGWT is severly lacking a nice date/time picker/chooser. So for now, you need to use a work-around. The solution is to use the date picker in combination with a suitable method of selecting time. The standard TimeItem in smartGWT is particularly shoddy and user-unfriendly.

What you want is a spinner for the hours, a spinner for the seconds and a decent defaulting to today's date and time.

Well, fret no more, here is a solution. For the purposes of this example, we are implementing a send timestamp where the user selects a date and time to send an item. It gets placed on a dynamic form item so that it can be added to a layout.

Note that I set the borders here so that you can see the way that it's laid out. You will want to remove those lines in the real world.

  final DynamicForm scheduleForm = new DynamicForm();
  DateItem sendDate  = new DateItem();
   sendDate.setDisplayFormat(DateDisplayFormat.TOSERIALIZEABLEDATE);
  sendDate.setEnforceDate(true);
  sendDate.setRequired(true);
  sendDate.setInputFormat("YMD");
  sendDate.setTitle("Send at:");

  // This part sets up the spinners for choosing a time to send at
  // We need to default it to now
       
  Date rightNow= new Date();
  int hour= rightNow.getHours();
  int min=rightNow.getMinutes();

  SpinnerItem sendTimeHr = new SpinnerItem();
  sendTimeHr.setName("sendTimeHr");
  sendTimeHr.setMax(23);
  sendTimeHr.setMin(0);
  sendTimeHr.setTitle("Time:");
  sendTimeHr.setWidth(2);
  sendTimeHr.setDefaultValue(hour);

  SpinnerItem sendTimeMin = new SpinnerItem();
  sendTimeMin.setName("sendTimeMins");
  sendTimeMin.setMax(59);
  sendTimeMin.setMax(0);
  sendTimeMin.setTitle(" ");
  sendTimeMin.setDefaultValue(min);
       
  scheduleForm.setNumCols(6);
  scheduleForm.setWidth(414);
  scheduleForm.setBorder("2px solid black");
  scheduleForm.setCellBorder(1);
  scheduleForm.setFields(sendDate,sendTimeHr,sendTimeMin);

Getting current time in GWT

The Calendar class isn't supported in GWT because the Java cannot be compiled into JavaScript.

So for now, you need to use the deprecated Date class in Java:

  import java.util.Date;
  .
  .
  .
  Date rightNow= new Date();
  int hour= rightNow.getHours();
  int min=rightNow.getMinutes();

I am still trying to find a better supported way to solve this problem, but for now, deprecated code seems to be the best solution available.

Wednesday 17 February 2010

How to add a Date and Time popup to smartGWT

There are a lot of queries about how to add a popup for selecting time and date in smartGWT. The bottom line is that smartGWT is lacking a single widget to do this, so you have to use a DateItem and TimeItem together.

Here is some sample code that adds these items to a VLayout call leftPanel:

 final DynamicForm scheduleForm = new DynamicForm();
 DateItem sendDate  = new DateItem();
 TimeItem sendTime = new TimeItem();
       
 scheduleForm.setFields(sendDate,sendTime);
 leftPanel.addMember(scheduleForm);