Tapestry 5.3:表单内部的组件:区域

时间:2015-05-28 22:07:37

标签: ajax hibernate components tapestry zone

我有一个用于编辑db实体的组件。它在onSuccess()上有@CommitAfter。当它在单独的页面上时,它工作正常。我点击更新按钮,它会保存数据并重定向到查看页面。

现在我想在列表页面上重复使用它。通过单击项目,它应该出现。在编辑并单击组件上的更新按钮后,它应该将项目保存到数据库并隐藏自己。

为了实现这个目的,我修改了组件,以便为其表单设置区域ID。将组件放在列表页面的区域内,为每个项目添加了带有事件onSelectItem的链接,它为组件设置区域ID并返回区域的主体。

它确实显示了组件,我可以编辑字段并点击更新按钮。它更新了项目,但将整个页面重定向到了查看页面。我试图在onSuccess()中返回null - 但在这种情况下它没有将数据保存到db并且区域也没有刷新。我还尝试使用@InjectPage从组件调用页面类并返回page.zone.getBody() - 这会重新加载区域,但仍然不保存数据,尽管所有方法都通过了w / o异常。在组件内调用特定于页面的代码也太糟糕了。我的其他自定义ajax调用使用@CommitAfter在方法中将数据保存到db。

所以我的问题是在Tapestry中这样做的正确方法是什么?

ContactsList.tml

<html t:type="layout" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd" xmlns:p="tapestry:parameter">
    <t:form>
       ... list of contacts linked to onSelectContact()
    </t:form>

    <t:zone id="editContact" t:id="editContactZone">
        <t:if test="selectedContact">
            <t:contactform t:id="contactForm" />
        </t:if>
    </t:zone>
</html>

ListPage.java

public class ContactsList{
    @InjectComponent
    private Zone editContactZone;

    @InjectComponent("contactForm")
    private ContactForm contactForm;

    @Property
    private Contact selectedContact;

    public Object onSelectContact(@RequestParameter(value = "id", allowBlank = false) Integer id) {
        selectedContact = getContactById(id);
        if (selectedContact != null) {
            contactForm.setContact(selectedContact);
            contactForm.setFormZone(editContactZone.getClientId());
        }

        return editContactZone.getBody();
    }
}

ContactForm.tml

<div xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd" xmlns:p="tapestry:parameter">

    <t:form t:id="editContactForm" zone="prop:zone">
        .... contact fields
    </t:form>
</div>

ContactForm.java

public class ContactForm{
    @InjectComponent("editContactForm")
    private Form editContactForm;

    @Property
    private String zone;

    @InjectPage
    private ContactList listPage;

    @InjectPage
    private ViewContact viewContact;

    @Property
    protected Contact contact;

    public void setContact(Contact contact) {
        this.contact = contact;
    }

    public void setFormZone(String zone){
       this.zone = zone;
    }

    @CommitAfter
    public Object onSuccess() {
       parseContact();
       storeContact(); // calls DAO.store(contact)

       return zone == null ? viewContact : listPage.onSelectContact(0); //don't like this in component code but at least it returns zone's body 
    }
}

1 个答案:

答案 0 :(得分:1)

您可以将Block组件参数传递给包含要在@OnSuccess之后呈现的标记的ContactForm。

或许更好的关注点分离是触发ContactForm中的一个事件,它会冒泡到页面?例如:

ContactForm.java

@Inject ComponentResources resources;

@CommitAfter
public void onSuccess() {
   storeContact();
   resources.triggerEvent("contactSaved", new Object[] { contact }, null);
}

ContactsList.java

@Inject AjaxResponseRenderer ajaxRenderer;
@Inject Zone someZone;
@Property Contact contact;

public void onContactSaved(Contact contact) {
    this.contact = contact;
    ajaxRenderer.addRender(someZone);
}

另外,你为什么要使用@RequestParameter?为什么不使用事件上下文?

ContactsList.tml

<t:loop source="contacts" item="contact">
    <t:eventlink event="selectContact" context="contact">Edit ${contact.name}</t:eventlink>
</t:loop>

ContactList.java

Block onSelectContact(Contact contact) {
   // doStuff
}