【问题标题】:Tapestry 5.3: Component with form inside t:zoneTapestry 5.3:在 t:zone 内具有表单的组件
【发布时间】:2015-08-11 15:07:01
【问题描述】:

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

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

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

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

所以我的问题是在 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 
    }
}

【问题讨论】:

  • 请分享您的代码。它可能就像返回一个 Block 一样简单,但是如果没有代码形式的实现细节,就无法判断。
  • @joostschouten,添加了我的代码

标签: ajax hibernate components tapestry zone


【解决方案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
}

【讨论】:

  • 谢谢。我喜欢你触发事件的建议。我重写了两页。但是 ContactList 页面仍然没有将项目保存到 db,EditContact 页面可以,尽管两个页面的组件代码完全相同。有什么建议吗?
  • 没有代码很难说。 contactForm.setContact(...)contactForm.setFormZone(...) 代码非常奇怪。您实际上应该只是在页面上设置属性,而不是在另一个组件中设置字段。您的组件应该类似于
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多