SwapHandler
Decouple your UI logic with distinct Event Handlers.
The Philosophy
As applications grow, Controllers tend to accumulate "UI Spaghetti Code".
- "When a user saves a task..."
- Update the list
- Update the sidebar count
- Update the project progress bar
- Show a toast
SwapHandler lets you break this logic into small, independent classes.
How it Works
1. The Interface
Implement ISwapEventHandler<TEvent>. The generic type TEvent is a simple POCO class representing the event.
public record TaskCompletedEvent(int TaskId);
[SwapHandler]
public class TaskListHandler : ISwapEventHandler<TaskCompletedEvent>
{
public Task HandleAsync(TaskCompletedEvent evt, SwapResponseBuilder builder, CancellationToken ct)
{
// Logic specific to the Task List
builder.AlsoUpdate(SwapElements.TaskRow(evt.TaskId), "", null, SwapMode.Delete);
return Task.CompletedTask;
}
}
2. Auto-Discovery
The [SwapHandler] attribute ensures your handler is automatically discovered and registered by AddSwapHtmx(). No manual DI registration is needed.
3. Execution Order
Handlers run in parallel* by default. The SwapResponseBuilder is thread-safe, aggregating all AlsoUpdate calls into a single JSON/HTML response.
(Technically Task.WhenAll, they run concurrently on the server).
Advanced Usage
Priority
You can control the order if needed (though you rarely should need to).
[SwapHandler(Priority = 100)] // Runs earlier (Higher = Earlier)
public class CriticalHandler ...
Shared Services
Since Handlers are resolved from DI, you can inject your Repositories, DbContext, or Services just like in a Controller.
public class StatsHandler : ISwapEventHandler<TaskCompletedEvent>
{
private readonly IStatsService _stats;
public StatsHandler(IStatsService stats) => _stats = stats;
// ...
}