Wicket:隐藏组件而不必添加其所有子组件

Wicket: hide a component without having to add all its children

我一直在 Wicket 中做一个项目,我经常发现自己处于令人讨厌的境地。假设我有一段标记,仅在某些条件适用时才显示,如下例所示:

<div wicket:id="myContainer">
    <div wicket:id="label1"></div>
    <div wicket:id="label2"></div>
    <div wicket:id="label3"></div>
    <div wicket:id="label4"></div>
</div>

在我的 Java 代码中:

WebMarkupContainer myContainer = new WebMarkupContainer("myContainer");
add(myContainer);

if(myDataObject != null){
    myContainer.add(new Label("label1", myDataObject.getData1());
    myContainer.add(new Label("label2", myDataObject.getData2());
    myContainer.add(new Label("label3", myDataObject.getData3());
    myContainer.add(new Label("label4", myDataObject.getData4());
} else{
    //HAVING TO DO THIS IS ABSURD!
   myContainer.add(new Label("label1", "");
   myContainer.add(new Label("label2", "");
   myContainer.add(new Label("label3", "");
   myContainer.add(new Label("label4", "");
   myContainer.setVisible(false);
}

如您所见,即使在我不打算显示的情况下,我也被迫将虚拟组件添加到容器中,否则 Wicket 会抛出异常,说我在标记中有组件还没有在代码中添加。

对我来说,这很荒谬,必须实例化我不会展示的额外组件是浪费、耗时的,并且不必要地降低代码的可读性。

我希望这只是我对 Wicket 的无知,希望有人能告诉我一种方法,让我可以 "discard a component and all children"。

不要以为成本高

不可见组件不会执行很多方法,最重要的方法是onRender() 和onComponentTag()。模型不执行 getObject()。 从html代的角度可见成本为零。 附加信息: https://ci.apache.org/projects/wicket/guide/7.x/guide/componentLifecycle.html

根据当前版本 7.5.0 检查我的知识

我认为组件(不可见)必须存在,这是正常的 Wicket 理念。隐形组件是轻量级的。

顺便说一句,我不确定您的 myDataObject 是 wicket 模型。 我同意文档中的建议:使用模型

没有这样的代码会更清晰 'if' - 我不喜欢使用分支实例化 - 但使用正确的模型。

避免在构造函数中使用过多 "active" 代码,例如不获取值,让通过模型有条件地(惰性)获取。 捕获 Wicket 构造函数中抛出的异常是丑陋的。但是应用程序可以很好地捕获渲染阶段的异常。

最后,请记住,这是使组件隐藏的两种策略,一种是静态的,第二种是动态的: https://ci.apache.org/projects/wicket/guide/7.x/guide/keepControl.html#keepControl_1

你可以大大改进你的代码,这样就不会那么痛苦了:)

这是使用 CompoundPropertyModel 的好地方。

此外,只需控制容器onConfigure()中的可见性即可。

WebMarkupContainer myContainer = new WebMarkupContainer("myContainer", new CompoundPropertyModel(myDataObject))
{
    public void onConfigure()
    {
        setVisible( this.getModelObject() != null);
    }
}

add(myContainer);

myContainer.add(new Label("data1"));
myContainer.add(new Label("data2"));
myContainer.add(new Label("data3"));
myContainer.add(new Label("data4"));

备选

你使用 WebMarkupContainer 的方式表明你也可以在那里使用 Panel 为这个 "myDataObject"

构建一个漂亮的显示组件

Java

public class MyDataObjectPanel extends Panel
{
    public MyDataObjectPanel(String id, IModel<MyDataObject> myDataObjectModel)
    {
        super(id,  new CompoundPropertyModel(myDataObjectModel);
        this.add(new Label("data1"));
        this.add(new Label("data2"));
        this.add(new Label("data3"));
        this.add(new Label("data4"));
    }

    public void onConfigure()
    {
        setVisible( this.getModelObject() != null);
    }

}

HTML

<wicket:panel>
    <div wicket:id="data1"></div>
    <div wicket:id="data2"></div>
    <div wicket:id="data3"></div>
    <div wicket:id="data4"></div>
</wicket:panel>

然后所有你想显示的地方,就用这个面板。


我会反对这个(因为它会让你的代码更复杂,我认为你不会赢得很多性能),但如果你真的关心不添加元素到wicket-component-tree,你可以下一个代码。它决定是否显示专用组件并替换实际组件:

public class MainComponent {

    @Override
    protected void onConfigure()
    {
        MyDataObject obj = getDataObjectFromSomeModel();
        if (obj == null) {
            this.addOrReplace( new EmptyPanel("dataPanelId").setVisible(false));
        }
        else {
            this.addOrReplace( new MyDataObjectPanel("dataPanelId"));   
        }
    }
}

我现在没有时间尝试,但我很确定

} else{
  myContainer.setVisible(false);
}

应该可以。 如果根本不渲染父组件,Wicket 不会抱怨子组件丢失。