In this post I show a simple component that is using that feature. The component makes a mathematical question and let's the user answer to it. The functionality is following:
- Question contains two integer values and an operation (+ or -)
- New values and operation is randomly generated when component is created
or if user asks for it. - When user answer to the question, a message of success or failure is shown
The example shows that it is only needed to send the answer back to the server when answered. The original values and the operation are already there.
So, let's begin. First I decided to model the value handling as enum
enum Operation { ADDITION("+") { @Override public long calculate(long val1, long val2) { return val1 + val2; } }, SUBTRACTION("-") { @Override public long calculate(long val1, long val2) { return val1 - val2; } }; private final String name; private Operation(String name) { this.name = name; } public abstract long calculate(long val1, long val2); }
Next the component is needed. First let's create a skeleton of all properties it needs:
public class MathQuestion extends EnhancedElement { @EmbeddedElement private SimpleLabel answer = new SimpleLabel(); private Operation operation; @EmbeddedAttribute private long val1; @EmbeddedAttribute private long val2; @EmbeddedAttribute public String operation() { return operation.name; } }
So the component contains the values and the operation as text which are shown to the user.
That component contains also premade component
SimpleLabel
that is used to contain the actual answer. You may find similar example from tutorial.Next let's add the rest.
public MathQuestion() { tryAgain(); } @RemoteMethod public void tryAgain() { Random rand = new Random(); val1 = rand.nextInt(201) - 100; val2 = rand.nextInt(201) - 100; operation = Operation.values()[rand.nextInt(2)]; answer.setValue(""); refresh(); } @RemoteMethod public void guess(Long guess) { if (guess != null) { if (guess == operation.calculate(val1, val2)) { answer.setValue("Your answer was correct :-)"); } else { answer.setValue("Your answer was incorrect :-("); } answer.refresh(); } }
Now, I have added to remote methods that can be called from the client. The
tryAgain()
simply resets the values and refreshes the component. The guess()
takes a guess from the client and does the calculation to check if the answer is correct. Then it sets a proper message to answer-label and refreshes it.Ok, that was the Java-side. Next the template is needed:
<xsl:template match="MathQuestion"> <div id="{@id}"> <xsl:call-template name="MathQuestion" /> </div> </xsl:template> <xsl:template match="MathQuestion.update"> <replaceInner id="{@id}"> <xsl:call-template name="MathQuestion" /> </replaceInner> </xsl:template> <xsl:template name="MathQuestion"> <xsl:value-of select="@val1" />   <xsl:value-of select="@operation" />   <xsl:value-of select="@val2" />   =   <input type="text" size="3" id="{@id}_guess" /> <input type="button" class="button" value="Answer" onclick="contextfw.call('{@id}', 'guess', $('#{@id}_guess').val());" />  <xsl:apply-templates select="answer" /> <br/> <input type="button" class="button" value="Try again" onclick="contextfw.call('{@id}', 'tryAgain');" /> </xsl:template>
That is about it. The template is quite straight forward. All the properties that were bound as attributes are shown, and elements are put to the desired places. Then with some jQuery answer is read from input and then the request is made.