This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
For HTMX users and typical server side only rendering. No JavaScript. What ways have you found to create self-contained "components". By that I mean, say I want to create a "visitor counter". And I want a "live chat" and so on. Each is like a "widget component". So that I can then simply drop them on any page anywhere and they work without having to externally setup anything. One more constraint is, I also want those widgets to interact: 1. One of them might need to access a selection made in another, but I want to decouple them, so they don't know about each other. 2. And when the user does something in one, it might cause others to refresh or change what they're displaying.
Would you be open to using another framework? I've been working for a few months on something similar to HTMX, but for which each hiccup fn is a component/widget that can be dropped in anywhere. I plan to release it soon-ish. If there's interest I might put more work into it. I tried to fix some downsides of HTMX, most notably the awkward action at a distance that required manual handling of html IDs.
Ya, alternative to HTMX would work as well. As long as it's just Clojure JVM on the backend without ClojureScript or JS, beyond including a script tag in your pages.
What I'm doing now is the following:
1. Create a namespace say: my-app.live-chat
2. Have a make-routes function where I define routes related to it, prefixed with the name of the component, so /live-chat/send-message
3. Have a render function which returns the hiccup for the component.
4. Then if I want to use it in another page, I just call (live-chat/render)
5. And in my app routes I merge the routes for it.
I'm keeping styling global. Cause I find that helps create a unified theme between components. I'm trying to use similar .class though between my components.
Now for self-contained components this work alright. But if I need them interacting between each other is where I'm a bit stuck.
I'm trying out the HX-Trigger. So each component publish events. That way other components can subscribe and react to them. But that's not totally decoupled. And I have a use-case where I want to grab the input entered in one component to use it in another. I don't want to couple the id
like you said. So I was thinking of having a field-change HX-Trigger on change and on load. That other components would listen too. But my problem is it's not that they need to do something when the value changes. It's that next time the user interacts with them they need to know the currently set value. And since I can't store state I don't think within each component with HTMX, I'm not sure how to do that.
Now I thought I can inject the id
, so when I call (render) some components can take additional inputs. One of them could be the id of some other field it should use to grab the value it needs from, etc.
I've also wondered about using out of band swap instead of events. I could inject a function in the render of one component, that calls the function when it re-renders itself, so another component can render itself alongside it as a OOB swap.
That's where I'm at with HTMX haha.
I can't say it's an exemplar, but you might want to check outhttps://github.com/markbastian/keg-party/tree/main/src/keg_party. It's a little hmtx project I did that has some of the features you discuss (e.g. events in different page locations). In my experience with htmx so far (both on this project and some professional use), here are a few patterns I've learned:
• Always write components as pure functions. It should just be data in -> hiccup out.
• Anything you want to re-render should follow the pattern of & attrs
in the tail position so you can separate your hx- logic from the view. https://github.com/markbastian/keg-party/blob/main/src/keg_party/pages/feed.clj#L19-L23. Honestly, I should refactor all of my code to do this.
• To prevent an explosion of endpoints as well as allow for out of band updates (so you can do inter-component updates), I've found two patterns that I think work quite well:
◦ In the project here, I use websockets for all comms. You just send events from the FE, process them, and broadcast updates that might hit several clients and/or several elements in the FE. The only downside to this approach is you lose some locality of behavior. I actually think it works really well, though.
◦ Another pattern I've found useful is to have a GET endpoint that returns the page and a single POST endpoint that takes an "action" parameter so you generally only need two endpoints per page (single path) -- the initial load and an endpoint that handles all actions.
If you do the above, you can have a "component" library of pure data to hiccup functions that are decoupled from htmx, then you pass in the attributes which do the wiring. HTH.
In this repo, yes. If you’re doing htmx the components won’t talk to each other on the front end. You can use a post as well, but you’ll still need to do multi-component updates via oob swaps in the response.
My issue is the coupling between them. Not sure how to make it so it's not like components that are built together.
Also, you can have components talk to each other client side a bit if you do:
<button onclick="htmx.trigger('#some-component', 'some-event')"
(meta ^:x [:a 1])
=> {:x true}
(def aaa [:a 1])
(meta ^:x aaa)
=> nil
Is there a shorthand to add some metadata to the value of aaa
?
(Not with-meta
)the value or the var?
That shorthand is a reader thing, not a runtime thing. So (meta ^:x aaa)
adds metadata to the symbol (not its bound value).
(meta (vary-meta aaa assoc :x true))
does what you want but is not really shorthand
The value, unless I misunderstood which one meta
is getting.
For example, I want to pass aaa
as an argument to a function.
Inside the function, I'd check if the value has a given metadata key.
vary-meta
is probably closest
Why not use with-meta
?
we have a mothballed meta+>
/ meta+>>
that's more concise, never got around to adding it
@U04V70XH6 I was looking for something compact, easy to one-line. But if there isn't anything I'll try to find something a little more elegant in my approach.
user=> (defn f [v] (println (meta v)) v)
#'user/f
user=> (def aaa ^:x [:a 1])
#'user/aaa
user=> (f aaa)
{:x true}
[:a 1]
user=> (f (with-meta aaa {:y 2}))
{:y 2}
[:a 1]
user=> (f (vary-meta aaa assoc :y 2))
{:x true, :y 2}
[:a 1]
user=>
(just to be explicit about things)well you can put the big thing in a function and then it's short :)
😅 It's true