Check if ValueListBoxes are answered in GWT

Go To StackoverFlow.com

0

I'm creating a survey for users to fill out and one of the requirements is to implement a progress bar that fills up as the user answers questions.

The bug I can't quite wrap my head around is with list boxes. If I select a value the counter goes up just fine, but if I select another value the counter increases again, when it should stay the same value.

Basic example below:

  • SELECT VALUE
    • TRUE
    • FALSE

Percent Complete: 0% (Default drop down list with "Select Value" as the default value)

  • TRUE
    • SELECT VALUE
    • FALSE

Percent Complete: 2%

  • FALSE
    • SELECT VALUE
    • TRUE

Percent Complete: 4% (Should be 2% because the question has already been answered)

This is the code for the change handler:

        final ValueChangeHandler<Boolean> booleanChangeHandler = new ValueChangeHandler<Boolean>()
        {
            @Override
            public void onValueChange(final ValueChangeEvent<Boolean> event)
            {
               Boolean value = event.getValue();
               changeAnsweredQuestionTotal(String.valueOf(value));  
            }                
        };  

And this changes the progress bar. I also use it to check if textboxes have been filled out.

public void changeAnsweredQuestionTotal(String value)
{
    //Window.alert(value);
    boolean isEmpty = (value == null) || value.equalsIgnoreCase("Null") ? true : value.isEmpty();
    Integer answered;
    Integer totalQuestions;

    String text = this.getQuestionsAnswered().getText().substring(0, 2);
    text= text.replaceAll("\\s+", "");  

    answered = text.isEmpty() ? 0 : Integer.valueOf(text);
    answered = (answered < 0) ? 0 : answered;
    totalQuestions = this.getTotalQuestions().getValue().isEmpty() ? 0 : Integer.valueOf(this.getTotalQuestions().getValue());

    String result;

    if (isEmpty)
    {
        answered = answered - 1;
        answered = (answered < 0) ? 0 : answered;
        result = answered + " questions answered. ";
    }
    else
    {
        if (!value.equalsIgnoreCase("null"))
        {      
            answered = answered > totalQuestions ? totalQuestions : answered + 1;
        }
        result = answered + " questions answered. "; 
    }

    Integer percent = (answered*100)/totalQuestions;
    percent = (percent > 100) ? 100 : percent;
}

Any help would be very appreciated.

2012-04-03 20:07
by James Hush


1

First, I think your method "changeAnsweredQuestionTotal" is too complex and need to be refactored if you decide to use it in future.

In following I will describe how I would solve it. I'm sure there other ways also.

The idea is to have a counter (in the case a Map<String,Integer> ) for the answers. The key is the control name(for ex. question1 or question2 ...) the value can be 0 or 1 depending if it is answered or not.

You should have a custom ValueChangeHandler for every list widget. This handler will know the "source"(will be used as key in the counter) and will know to update the counter depending on the value.

At the end you create one more handler, one instance, and assign to all list widgets to update the progress bar.

Here is the code for the custom handler:

public class QuestionChangeHandler<T> implements ValueChangeHandler<T>{

  private String source;

  private Map<String, Integer> counter;

  public QuestionChangeHandler(String source, Map<String, Integer> counter) {
    super();
    this.source = source;
    this.counter = counter;
  }



  @Override
  public void onValueChange(ValueChangeEvent<T> event) {
    T value = event.getValue();
    if (value == null) {
      counter.put(source, Integer.valueOf(0));
    } else {
      counter.put(source, Integer.valueOf(1));
    }
  }


  /**
   * @return the source
   */
  public String getSource() {
    return source;
  }

}

Here is small working app with two lists:

public class AnswersApp implements EntryPoint {

  private VerticalPanel mainPanel = new VerticalPanel();
  private Label answersLabel = new Label("Answers");
  private Label answerNumber = new Label("0");

  private ValueListBox<Boolean> question1 = new ValueListBox<Boolean>(new BooleanRenderer(), new BooleanKeyProvider());
  private ValueListBox<Boolean> question2 = new ValueListBox<Boolean>(new BooleanRenderer(), new BooleanKeyProvider());

  private ValueChangeHandler<Boolean> updateHandler;

  private HashMap<String, Integer> counter = new HashMap<String, Integer>();

  public void onModuleLoad() {
    initUpdateHandler();
    List<Boolean> values = new ArrayList<Boolean>();
    values.add(Boolean.TRUE);
    values.add(Boolean.FALSE);
    question1.setAcceptableValues(values);
    question2.setAcceptableValues(values);
    question1.addValueChangeHandler(new QuestionChangeHandler<Boolean>("q1", counter));
    question2.addValueChangeHandler(new QuestionChangeHandler<Boolean>("q2", counter));

    question1.addValueChangeHandler(updateHandler);
    question2.addValueChangeHandler(updateHandler);

    mainPanel.add(question1);
    mainPanel.add(question2);
    mainPanel.add(answersLabel);
    mainPanel.add(answerNumber);

    RootPanel.get().add(mainPanel);
  }


  private void initUpdateHandler() {
    updateHandler = new ValueChangeHandler<Boolean>() {

      @Override
      public void onValueChange(ValueChangeEvent<Boolean> event) {
        recalculateAnswers();

      }
    };

  }

  private void recalculateAnswers() {
    Set<String> keys = counter.keySet();
    int answers = 0;
    for (String key : keys) {
      Integer value = counter.get(key);
      if (value != null && value.intValue() == 1) {
        answers++;
      }
    }
    answerNumber.setText(Integer.toString(answers));
  }
}

Here the result is the number of answers, I'm sure you can continue from there.

2012-04-03 21:38
by Goran Nastov