0

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

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

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

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

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

联系人列表.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();
    }
}

联系表格.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 
    }
}
4

1 回答 1

1

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

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

ContactForm.java

@Inject ComponentResources resources;

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

联系人列表.java

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

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

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

联系人列表.tml

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

联系人列表.java

Block onSelectContact(Contact contact) {
   // doStuff
}
于 2015-05-29T09:42:44.310 回答