在用户注册的时候,我们想要给他们选择是否预定我们的时事资讯,那么我们就要新增一个选择框:
界面变的稍微复杂了,但是也给了我们一个学习新组件的机会。
当用户点击该复选框,复选框应该消失,接受用户的电子邮件的文本框应该会出现。
在页面中的代码:
<tr>
<t:if t:test="subscribe">
<td><t:label t:for="email"/></td>
<td>
<input type="text" t:type="textfield" t:id="email" t:value="email"/>
</td>
<t:parameter t:name="else">
<td colspan="2">
<input type="checkbox" t:type="checkbox" t:value="subscribe"
οnclick="this.form.submit()"/>
Check the box to subscribe to our Newsletter.
</td>
</t:parameter>
</t:if>
</tr>
让我们看看它们是怎么在一起工作的,首先,这只是一行,放在
Registration.tml
的单选按钮之下,这一行包含了一个
t:if
标签。
<t:if t:test="subscribe">
...
</t:if>
组件唯一的参数就是
test
,他提供了一个
boolean
值,它默认的前缀是
prop
所以
Tapestry
会到
page class
中调用
getSubscribe
方法。如果这个方法返回
true
,那么在
If
组件下的内容将显示:
<td><t:label t:for="email"/></td>
<td>
<input type="text" t:type="textfield" t:id="email" t:value="email"/>
</td>
这个
IF
组件还有一个被命名为
else
的
Patameter
项,这个
Patameter
提供这个在
getSubscribe
为
false
时,将会展现的内容。
在
<t:parameter t:name="else"> ... </t:parameter>
块中萎缩这一个在
HTML
控件中的组件,这个组件就是
checkbox
,注意看他的
value
有一个值叫
subscribe
,是和
IF
组件的
test
属性一样的。
而且这个
Checkbox
组件居然和一个
js
勾搭在了一起,当
checkbox
被点击的时候,就会惹到这个
javascript
,不过这个
JS
只是提交了这个表单。
让我们看看他们是怎么互相勾搭在一起的,
刚开始的时候,
Registration
页面第一次被加载,
subscribe
被认为是
false
,那么这个
checkbox
就被显示了出来。如果这个用户去点击了这个
checkbox
,那么这个
form
就被提交了,然后
subscribe
就被置为
true
,我们想要
page
去记住这个值,那就只要让这个值
persistent.
了。那么那个输入
email
的文本框就出现了。
我们需要在
page class
中加入能让
subscribe
持久化的属性,和保存
email
的属性:
@Persist
private boolean subscribe;
private String email;
public boolean isSubscribe()
{
return subscribe;
}
public void setSubscribe(boolean subscribe)
{
System.out.println("Setting subscribe: " + subscribe);
this.subscribe = subscribe;
}
public String getEmail()
{
return email;
}
public void setEmail(String email)
{
this.email = email;
}
在
setter
方法中有个
output
方法,这将方便的告诉我们这个
page class
是怎么工作的。
运行这个工程,输入用户名密码,并且选择接受订阅,一切都在掌控之中,
email
的输入框取代了
checkbox
。但是你也会发现别的问题,我们输入的用户名和密码都不见了,或者恢复到了默认值。如果你对前面的还有印象,你不会感到有任何的疑问,毕竟除了我们让它这么做不然
Tapestry
是不会保存任何东西的。这也很简单,只要在想要记住的属性前加上
@persist
就可以了:
@Persist
private String userName;
@Persist
private String password;
private String password2;
@Persist
private String email;
@Persist
private Gender gender = Gender.FEMALE;
实际上密码是不用持久化的,因为它永远都不会显示,但让他持久化一会儿就有点小用。现在页面能好好的工作了,但是有一个问题,当我们选择了接受,我们就没法再取消,因为
subscribe
被赋值为
true
并保持在
session
中,我们没有提供一个方法去再让它变回
false
。除非你把浏览器关了重新来,但是白痴才会这么做。
为了解决这个问题,我们在
email
下面加上另外一个
checkbox
。
<td>
<input type="text" t:type="textfield" t:id="email" t:value="email"/>
<input type="checkbox" t:type="checkbox"
t:value="unsubscribe" οnclick="this.form.submit()"/>
I don't want to subscribe
</td>
当然还要在
Registration.java
中加入
unsubscribe
属性:
private boolean unsubscribe;
public boolean isUnsubscribe()
{
return unsubscribe;
}
public void setUnsubscribe(boolean unsubscribe)
{
this.unsubscribe = unsubscribe;
}
当我们点击这个
checkbox
时,
form
被提交,
unsubscribe
被置为
true
。但是我们怎么样才能使
unsubscribe
为
true
的时候
subscribe
被置为
false
呢?很自然的,我们需要在
form
提交的时候做这个事情:
void onSubmitFromRegistrationForm()
{
System.out.println("The form was submitted!");
if (unsubscribe) subscribe = false;
}
现在唯一的问题就是密码在页面重载时不能重新显示,虽然我们已经让密码的属性持久化了。其实这是很自然的,
passwordFeild
组件不能重新显示它的值。但是我们不能让我们的用户在每次页面重新加载时,都重新输入密码,这是不道德的。
下面作者想出了一个天才的解决方案:就是在提交后把密码输入框隐藏。
<t:if t:test="passwordNotSubmitted">
<tr>
<td><t:label t:for="password">
Label for password</t:label>:</td>
<td><input type="text" t:type="passwordfield"
t:id="password"
t:value="password"/></td>
</tr>
<tr>
<td><t:label t:for="password2">
Label for password 2</t:label>:</td>
<td><input type="text" t:type="passwordfield"
t:id="password2"
t:label="Repeat password" t:value="password2"/></td>
</tr>
</t:if>
并且在
class
中加:
public boolean isPasswordNotSubmitted()
{
return userName == null;
}
现在我们已经有了一个相当灵活的页面,只需要写少量的代码就能实现我们的目的。其中所有的方法都是在提交表单的处理事件中实现的。但是,这些都只是玩具代码,只是演示页面是如何变化的。我们的目的是注册一个用户,但是用于提交
form
的事件已经用于了不同的实现,那么我们该把代码写到哪里?