0
votes

I'd like a way to easily tie a widget back to the business object it is rendering. So when the user interacts with a widget I can easily determine the business object holding the data for that widget.

For example, if we imagine a calendar widget that we're going to implement with an AbsolutePanel. For each appt object we'll add a label to the calendar. Then when a user clicks on a label he can update the appt. So I need to know which appt object that label refers to.

For instance, if we look at the following code; if the label for an appointment receives a click, how can I find out to which appt it represented ? The only solution I can see is to create a ApptLabel sub-class for Label which would hold a reference to its appt. This is fine, but the example illustrates a more general need which is to associate widgets with data objects; however this would mean that every object that has a presence in a view needs to subclass a widget. that seems heavy - I expected to find something in the framework e.g. a string property in a widget that I can set to an object key

other approaches I tried; maintaining a map of Map -- this didnt work as the label object I create doesnt appear to be the same (in terms of the Object.equals which I guess is what HashMap uses)

class WidgetCalendar extends Composite { 
    AbsolutePanel m_panel = new AbsolutePanel();
    m_panel.setStylePrimaryName("calendar");
    m_panel.setPixelSize(width, height);

    public WidgetCalendar(ArrayList<BomAppt> appts) {
       initWidget(m_panel);
       for (BomAppt a : appts) {
          Label l = new Label();
          l.addClickHandler(new ClickHandler() {
    public void onClick(ClickEvent event) {
    // how do I know my BomAppt in here ?                   
       }

          m_panel.add(l, someX, someY);
       }
    }
}

Ideally I can do something like this class WidgetCalendar extends Composite { AbsolutePanel m_panel = new AbsolutePanel(); m_panel.setStylePrimaryName("calendar"); m_panel.setPixelSize(width, height);

    public WidgetCalendar(ArrayList<BomAppt> appts) {
       initWidget(m_panel);
       for (BomAppt a : appts) {
          Label l = new Label();
          l.setItemData(a.getUniqueId());
          l.addClickHandler(new ClickHandler() {
            public void onClick(ClickEvent event) {
              BomAppt a = BomAppt.getApptWithId(e.getItemData())
            }
          }
          m_panel.add(l, someX, someY);
       }
    }
}

This is the solution where I create a subclass, this seems heavy to me and I'd prefer something simpler

class ApptLabel extends Label {
    public ApptLabel(BomAppt a) {
      m_a = a;
  this.addClickHandler(new ClickHandler() {
    public void onClick(ClickEvent event) {
      m_a.doSomething();
            });
    }

    BomAppt m_a;
}

class WidgetCalendar extends Composite { 
    AbsolutePanel m_panel = new AbsolutePanel();
    m_panel.setStylePrimaryName("calendar");
    m_panel.setPixelSize(width, height);

    public WidgetCalendar(ArrayList<BomAppt> appts) {
       initWidget(m_panel);
       for (BomAppt a : appts) {
          BomLabel l = new BomLabel();
          l.addClickHandler(new ClickHandler() {
    public void onClick(ClickEvent event) {
    // how do I know my BomAppt in here ?                   
       }

          m_panel.add(l, someX, someY);
       }
    }
}
1

1 Answers

0
votes

For instance, if we look at the following code; if the label for an appointment receives a click, how can I find out to which appt it represented ?

By using Composite pattern you can find out which widget was clicked, initially you should create your own custom Appointment widget which is responsible for drawing one appointment. And in you Appointment widget you can have a set of other widgets, in your case, for Label add click handler. Once user clicks that label, you can execute business logic with its data and you can represent data.

public class Appointment extends Composite { 
      private AppointmentDetails data;
      public Appointment(AppointmentDetails data){
           draw(data);
      }

      private void draw(AppointmentDetails data){
         Label label = new Label();
         label.addClickHandler(new ClickHandler() {
         public void onClick(ClickEvent event) {
             // do your business logic with this AppointmentDetails
             }
         });
      }

}

After that you should have one Calendar widget which contains several Appointments. Keep in your mind: your classes each serve a single, very clearly defined purpose, separated from other classes with other clearly defined purposes.