Skip to content

Support for Flux<Rendering> and Flux<ModelAndView> for @RequestMapping handler methods #27652

Closed as not planned
@dsyer

Description

@dsyer

A handler method returning Flux<T> where T is "something that can render a template" would be quite useful, especially in the light of the popularity and ease of use of things like the @hotwired/turbo and htmx.org JavaScript modules. Those client libraries both have support for "streams" of HTML elements coming from the server, which get transcluded into the "main" page on the client. They also both support SSE streams containing HTML data. It would be nice to be able to render in both styles.

Webflux and MVC currently have support for SSE. E.g. with Webflux you can return Flux<String> or Flux<ServerSentEvent> from a handler method, but in both cases you have to render the data yourself. It would be handy to be able to delegate the rendering to a template engine, so Rendering (WebFlux) and ModelAndView (MVC) seem like a good fit. Thymeleaf also has some native (if a bit clumsy) support via ReactiveDataDriverContextVariable, so there is some prior art there. You could see this feature request as a generalization of that.

Simple example for Turbo on Webflux (for MVC just replace Rendering with ModelAndView) and SSE:

@GetMapping(path = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<Rendering> stream() {
	return Flux.interval(Duration.ofSeconds(2)).map(value -> event(value));
}

private Rendering event(long value) {
	return Rendering.view("stream").modelAttribute("value", value)
		.modelAttribute("time", System.currentTimeMillis()).build();
}

with a template (e.g. in mustache but could be thymeleaf etc.):

<turbo-stream action="append" target="load">
	<template>
		<div>Index: {{value}} Time: {{time}}</div>
	</temlate>
</turbo-stream>

The result would be an infinite stream, e.g.:

data: <turbo-stream action="append" target="load">
data: ...


data: <turbo-stream action="append" target="load">
data: ...


...

An example with HTMX and the HTML "stream" would be the same controller but with a different produces media type:

@GetMapping(path = "/updates", produces="text/vnd.turbo-stream.html")
public Flux<Rendering> stream() {
	return Flux.just(event("one"), event("two");
}

private Rendering event(String id) {
	return Rendering.view("update").modelAttribute("id", id)
		.modelAttribute("time", System.currentTimeMillis()).build();
}

with a template (e.g. in mustache but could be thymeleaf etc.):

<div htmx-swap-oob="true" id="{{id}}">
	<div>Time: {{time}}</div>
</div>

The result would be a concatenation of the 2 divs:

<div htmx-swap-oob="true" id="one">
	<div>Time: 1346876956</div>
</div>
<div htmx-swap-oob="true" id="two">
	<div>Time: 1346876987</div>
</div>

Metadata

Metadata

Assignees

Labels

in: webIssues in web modules (web, webmvc, webflux, websocket)status: supersededAn issue that has been superseded by anothertype: enhancementA general enhancement

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions