diff --git a/htmx-spring-boot/src/main/java/io/github/wimdeblauwe/htmx/spring/boot/mvc/HtmxHandlerInterceptor.java b/htmx-spring-boot/src/main/java/io/github/wimdeblauwe/htmx/spring/boot/mvc/HtmxHandlerInterceptor.java
index 0fe2779..0317131 100644
--- a/htmx-spring-boot/src/main/java/io/github/wimdeblauwe/htmx/spring/boot/mvc/HtmxHandlerInterceptor.java
+++ b/htmx-spring-boot/src/main/java/io/github/wimdeblauwe/htmx/spring/boot/mvc/HtmxHandlerInterceptor.java
@@ -38,6 +38,8 @@ public boolean preHandle(HttpServletRequest request,
setHxRetarget(response, method);
setHxReselect(response, method);
setHxTrigger(response, method);
+ setHxTriggerAfterSettle(response, method);
+ setHxTriggerAfterSwap(response, method);
setHxRefresh(response, method);
setVary(request, response);
}
@@ -108,7 +110,27 @@ private void setHxReselect(HttpServletResponse response, Method method) {
private void setHxTrigger(HttpServletResponse response, Method method) {
HxTrigger methodAnnotation = AnnotatedElementUtils.findMergedAnnotation(method, HxTrigger.class);
if (methodAnnotation != null) {
- response.setHeader(getHeaderName(methodAnnotation.lifecycle()), methodAnnotation.value());
+ response.setHeader(
+ getHeaderName(methodAnnotation.lifecycle()),
+ String.join( ",", methodAnnotation.value()));
+ }
+ }
+
+ private void setHxTriggerAfterSettle(HttpServletResponse response, Method method) {
+ HxTriggerAfterSettle methodAnnotation = AnnotatedElementUtils.findMergedAnnotation(method, HxTriggerAfterSettle.class);
+ if (methodAnnotation != null) {
+ response.setHeader(
+ HtmxResponseHeader.HX_TRIGGER_AFTER_SETTLE.getValue(),
+ String.join( ",", methodAnnotation.value()));
+ }
+ }
+
+ private void setHxTriggerAfterSwap(HttpServletResponse response, Method method) {
+ HxTriggerAfterSwap methodAnnotation = AnnotatedElementUtils.findMergedAnnotation(method, HxTriggerAfterSwap.class);
+ if (methodAnnotation != null) {
+ response.setHeader(
+ HtmxResponseHeader.HX_TRIGGER_AFTER_SWAP.getValue(),
+ String.join( ",", methodAnnotation.value()));
}
}
diff --git a/htmx-spring-boot/src/main/java/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxTrigger.java b/htmx-spring-boot/src/main/java/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxTrigger.java
index 57428e8..38f2d20 100644
--- a/htmx-spring-boot/src/main/java/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxTrigger.java
+++ b/htmx-spring-boot/src/main/java/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxTrigger.java
@@ -6,14 +6,17 @@
import java.lang.annotation.Target;
/**
- * Annotation to trigger client side actions on the target element within a response to htmx.
+ * Annotation to trigger client side events as soon as the response is received on the target element.
+ *
+ * You can trigger a single event or as many uniquely named events as you would like.
*
* @see HX-Trigger Response Headers
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface HxTrigger {
- String value();
+
+ String[] value();
HxTriggerLifecycle lifecycle() default HxTriggerLifecycle.RECEIVE;
}
diff --git a/htmx-spring-boot/src/main/java/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxTriggerAfterSettle.java b/htmx-spring-boot/src/main/java/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxTriggerAfterSettle.java
new file mode 100644
index 0000000..bd44d20
--- /dev/null
+++ b/htmx-spring-boot/src/main/java/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxTriggerAfterSettle.java
@@ -0,0 +1,28 @@
+package io.github.wimdeblauwe.htmx.spring.boot.mvc;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to trigger client side events after the
+ * settling step
+ * on the target element.
+ *
+ * You can trigger a single event or as many uniquely named events as you would like.
+ *
+ * @see HX-Trigger Response Headers
+ */
+@Target({ElementType.TYPE, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HxTriggerAfterSettle {
+
+ /**
+ * The events to trigger after the
+ * settling step
+ * on the target element.
+ */
+ String[] value();
+
+}
diff --git a/htmx-spring-boot/src/main/java/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxTriggerAfterSwap.java b/htmx-spring-boot/src/main/java/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxTriggerAfterSwap.java
new file mode 100644
index 0000000..3d1c511
--- /dev/null
+++ b/htmx-spring-boot/src/main/java/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxTriggerAfterSwap.java
@@ -0,0 +1,28 @@
+package io.github.wimdeblauwe.htmx.spring.boot.mvc;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to trigger client side events after the
+ * swap step
+ * on the target element.
+ *
+ * You can trigger a single event or as many uniquely named events as you would like.
+ *
+ * @see HX-Trigger Response Headers
+ */
+@Target({ElementType.TYPE, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HxTriggerAfterSwap {
+
+ /**
+ * The events to trigger after the
+ * swap step
+ * on the target element.
+ */
+ String[] value();
+
+}
diff --git a/htmx-spring-boot/src/main/java/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxTriggerLifecycle.java b/htmx-spring-boot/src/main/java/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxTriggerLifecycle.java
index 775a2d4..418de34 100644
--- a/htmx-spring-boot/src/main/java/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxTriggerLifecycle.java
+++ b/htmx-spring-boot/src/main/java/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxTriggerLifecycle.java
@@ -4,7 +4,9 @@
* Represents the HX-Trigger Response Headers.
*
* @see HX-Trigger Response Headers
+ * @deprecated use annotation {@link HxTriggerAfterSettle} or {@link HxTriggerAfterSwap} instead.
*/
+@Deprecated
public enum HxTriggerLifecycle {
/**
* Trigger events as soon as the response is received.
diff --git a/htmx-spring-boot/src/test/java/io/github/wimdeblauwe/htmx/spring/boot/mvc/HtmxHandlerInterceptorTest.java b/htmx-spring-boot/src/test/java/io/github/wimdeblauwe/htmx/spring/boot/mvc/HtmxHandlerInterceptorTest.java
index ef98d93..18a9c65 100644
--- a/htmx-spring-boot/src/test/java/io/github/wimdeblauwe/htmx/spring/boot/mvc/HtmxHandlerInterceptorTest.java
+++ b/htmx-spring-boot/src/test/java/io/github/wimdeblauwe/htmx/spring/boot/mvc/HtmxHandlerInterceptorTest.java
@@ -26,6 +26,13 @@ public void testHeaderIsSetOnResponseIfHxTriggerIsPresent() throws Exception {
.andExpect(header().string("HX-Trigger", "eventTriggered"));
}
+ @Test
+ public void testHeaderIsSetOnResponseWithMultipleEventsIfHxTriggerIsPresent() throws Exception {
+ mockMvc.perform(get("/with-trigger-multiple-events"))
+ .andExpect(status().isOk())
+ .andExpect(header().string("HX-Trigger", "event1,event2"));
+ }
+
@Test
public void testAfterSettleHeaderIsSetOnResponseIfHxTriggerIsPresent() throws Exception {
mockMvc.perform(get("/with-trigger-settle"))
@@ -40,6 +47,34 @@ public void testAfterSwapHeaderIsSetOnResponseIfHxTriggerIsPresent() throws Exce
.andExpect(header().string("HX-Trigger-After-Swap", "eventTriggered"));
}
+ @Test
+ public void testAfterSettleHeaderIsSetOnResponseIfHxTriggerAfterSettleIsPresent() throws Exception {
+ mockMvc.perform(get("/with-trigger-after-settle"))
+ .andExpect(status().isOk())
+ .andExpect(header().string("HX-Trigger-After-Settle", "eventTriggered"));
+ }
+
+ @Test
+ public void testAfterSettleHeaderIsSetOnResponseWithMultipleEventsIfHxTriggerAfterSettleIsPresent() throws Exception {
+ mockMvc.perform(get("/with-trigger-after-settle-multiple-events"))
+ .andExpect(status().isOk())
+ .andExpect(header().string("HX-Trigger-After-Settle", "event1,event2"));
+ }
+
+ @Test
+ public void testAfterSwapHeaderIsSetOnResponseIfHxTriggerAfterSwapIsPresent() throws Exception {
+ mockMvc.perform(get("/with-trigger-after-swap"))
+ .andExpect(status().isOk())
+ .andExpect(header().string("HX-Trigger-After-Swap", "eventTriggered"));
+ }
+
+ @Test
+ public void testAfterSwapHeaderIsSetOnResponseWithMultipleEventsIfHxTriggerAfterSwapIsPresent() throws Exception {
+ mockMvc.perform(get("/with-trigger-after-swap-multiple-events"))
+ .andExpect(status().isOk())
+ .andExpect(header().string("HX-Trigger-After-Swap", "event1,event2"));
+ }
+
@Test
public void testHeaderIsNotSetOnResponseIfHxTriggerNotPresent() throws Exception {
mockMvc.perform(get("/without-trigger"))
diff --git a/htmx-spring-boot/src/test/java/io/github/wimdeblauwe/htmx/spring/boot/mvc/TestController.java b/htmx-spring-boot/src/test/java/io/github/wimdeblauwe/htmx/spring/boot/mvc/TestController.java
index e9dd143..8026655 100644
--- a/htmx-spring-boot/src/test/java/io/github/wimdeblauwe/htmx/spring/boot/mvc/TestController.java
+++ b/htmx-spring-boot/src/test/java/io/github/wimdeblauwe/htmx/spring/boot/mvc/TestController.java
@@ -22,20 +22,55 @@ public String methodWithHxTrigger() {
return "";
}
+ @GetMapping("/with-trigger-multiple-events")
+ @HxTrigger({ "event1", "event2" })
+ @ResponseBody
+ public String methodWithHxTriggerAndMultipleEvents() {
+ return "";
+ }
+
@GetMapping("/with-trigger-settle")
@HxTrigger(value = "eventTriggered", lifecycle = HxTriggerLifecycle.SETTLE)
@ResponseBody
- public String methodWithHxTriggerAfterSettle() {
+ public String methodWithHxTriggerAndLifecycleSettle() {
return "";
}
@GetMapping("/with-trigger-swap")
@HxTrigger(value = "eventTriggered", lifecycle = HxTriggerLifecycle.SWAP)
@ResponseBody
+ public String methodWithHxTriggerAndLifecycleSwap() {
+ return "";
+ }
+
+ @GetMapping("/with-trigger-after-settle")
+ @HxTriggerAfterSettle("eventTriggered")
+ @ResponseBody
+ public String methodWithHxTriggerAfterSettle() {
+ return "";
+ }
+
+ @GetMapping("/with-trigger-after-settle-multiple-events")
+ @HxTriggerAfterSettle({ "event1", "event2" })
+ @ResponseBody
+ public String methodWithHxTriggerAfterSettleAndMultipleEvents() {
+ return "";
+ }
+
+ @GetMapping("/with-trigger-after-swap")
+ @HxTriggerAfterSwap("eventTriggered")
+ @ResponseBody
public String methodWithHxTriggerAfterSwap() {
return "";
}
+ @GetMapping("/with-trigger-after-swap-multiple-events")
+ @HxTriggerAfterSwap({ "event1", "event2" })
+ @ResponseBody
+ public String methodWithHxTriggerAfterSwapAndMultipleEvents() {
+ return "";
+ }
+
@GetMapping("/updates-sidebar")
@HxUpdatesSidebar
@ResponseBody