MarkupWriter を介してプログラムで html を追加するチュートリアルをたくさん見てきましたが、コンポーネントが使用されている場所に html を追加します。
body タグの直前に追加するようにライターに指示する方法はありますか?
また、コンポーネントの本体を取得するにはどうすればよいですか?
そこまで複雑にする必要はないと思う
@Environmental
private Heartbeat heartbeat;
@SetupRender
void setupRender(MarkupWriter writer) {
writer.element("div");
}
// let the body render as normal
@AfterRender
void afterRender(final MarkupWriter writer) {
Element wrapper = writer.element();
writer.end();
final String bodyMarkup = wrapper.getChildMarkup();
// remove the body
wrapper.remove();
heartbeat.defer(new Runnable() {
public void run() {
Element pageBody = writer.getDocument().find("html/body");
pageBody.raw(bodyMarkup);
}
});
}
ソリューション:
private Element pageBody;
private String componentBodyMarkup;
private Element wrapper;
@Environmental
private Heartbeat heartbeat;
@SetupRender
private RenderCommand setupRender() {
return new RenderCommand() {
public void render(MarkupWriter writer, RenderQueue queue) {
wrapper = writer.element("div");
RenderCommand renderBody = new RenderCommand() {
public void render(MarkupWriter writer, RenderQueue queue2) {
RenderCommand bodyRenderCommand = typeCoercer.coerce(componentResources.getBody(), RenderCommand.class);
queue2.push(bodyRenderCommand);
}
};
queue.push(renderBody);
}
};
}
@BeforeRenderBody
private boolean beforeRenderBody(MarkupWriter writer) {
return false;
}
@AfterRender
private void afterRender(MarkupWriter writer) {
pageBody = writer.getDocument().find("html/body");
writer.end();
componentBodyMarkup = wrapper.getChildMarkup();
wrapper.remove();
Runnable appendToBody = new Runnable() {
public void run() {
pageBody.raw(componentBodyMarkup);
}
};
heartbeat.defer(appendToBody);
}
コンポーネントの本体を取得するには、@Inject ComponentResources を呼び出して getBody() を呼び出す必要があります。
ボディの最後に何かを追加するには、もう少し考える必要があります。私は2つの方法を見ることができます。
@HeartbeatDeferred アノテーションを使用すると、他のすべてのコンポーネントがレンダリングされた後に DOM にアクセスできます。このようなもの:
public class MyComponent {
private Element body;
void setupRender(MarkupWriter writer) {
body = writer.getDocument().find("html/body");
}
@HeartbeatDeferred
void addToBody() {
body.text("Some text here");
}
}
もう 1 つの方法は、他のすべてのコンポーネントをネストする body タグの直下にコンポーネントを定義することです。このコンポーネントは、 @SetupRender メソッドでモデル オブジェクトを環境にプッシュします。最上位コンポーネントの子として定義されたコンポーネントは、 @Environmental アノテーションを使用してモデル オブジェクトを検索し、それに貢献できます。次に、最上位のコンポーネントがモデルをレンダリングします。
例えば:
<html>
<body>
<t:toplevelcomponent>
<t:childcomponent />
<div>...</div>
<div>...</div>
</t:toplevelcomponent>
</body>
</html>
public class TopLevelModel {
private List<String> contributions;
// getters and setters
}
public class TopLevelComponent {
@Inject
Environment environment;
public void setupRender() {
environment.push(TopLevelModel.class, new TopLevelModel());
}
public void afterRender(MarkupWriter writer) {
TopLevelModel model = environment.pop(TopLevelModel.class);
for (String contribution : model.getContributions()) {
// add text to the body tag
writer.getElement().text(contribution);
}
}
}
public class ChildComponent {
@Environmental
private TopLevelModel topLevelModel;
public void setupRender() {
topLevelModel.getContributions().add("Foo");
topLevelModel.getContributions().add("Bar");
}
}