Dynamic Pages with SlotKey and RenderContext
This is the default dynamic rendering pattern in SimplyPages.
SlotKey/Slot values also work with direct Component.render(context), but template-wrapped
rendering is the preferred reuse pattern for stable structures.
Define Slots and a Template Once
public final class ArticleView {
public static final SlotKey<String> ARTICLE_TITLE = SlotKey.of("article_title");
public static final SlotKey<String> ARTICLE_BODY = SlotKey.of("article_body");
public static final Template ARTICLE_TEMPLATE = Template.of(
ContentModule.create()
.withModuleId("article-view")
.withTitle("Article")
.withCustomContent(
new Div()
.withChild(new HtmlTag("h2").withInnerText(ARTICLE_TITLE))
.withChild(new Paragraph().withChild(Slot.of(ARTICLE_BODY)))
)
);
private ArticleView() {}
}
Template.of(...) and component.compile() are equivalent compile paths.
Render Per Request Using Context
@GetMapping("/articles/{id}")
@ResponseBody
public String article(@PathVariable String id) {
Article article = articleService.load(id);
RenderContext ctx = RenderContext.builder()
.with(ArticleView.ARTICLE_TITLE, article.title())
.with(ArticleView.ARTICLE_BODY, article.body())
.build();
return ArticleView.ARTICLE_TEMPLATE.render(ctx);
}
Request Mechanics
- Browser sends
GET /articles/{id}. - Controller loads article data.
- Controller maps fields into
RenderContext. - Template resolves slots and returns HTML.
Compile Policy for Reused Contexts
Use COMPILE_ON_FIRST_HIT only when you intentionally reuse a mutable context object.
RenderContext ctx = RenderContext.builder()
.withPolicy(RenderContext.RenderPolicy.COMPILE_ON_FIRST_HIT)
.with(ArticleView.ARTICLE_TITLE, article.title())
.with(ArticleView.ARTICLE_BODY, article.body())
.build();
If you later call ctx.put(key, newValue), compiled value for that key is replaced by live entry.
Anti-Pattern
Do not rebuild entire page/module trees on every dynamic update if only data changed.
Use stable templates + slots for data churn.
Do not share and mutate the same component/module instance concurrently across requests.