I’m working on a simple e-commerce platform and try to implement a session based cart (this is a follow up question to my last question).
I have a ‘classic’ controller for handling the cart and altering the session, now I want to add buttons for adding products to the product’s index view.
Btw: Where can I find documentation about the :action tag? I have no idea what it does and the doc’s search isn’t helping.
The corresponding controller at /cart/add/<id> only acknowledges the action with a 200er response.
It work’s despite it navigates the browser to the url it posts to. I’d like to make this request without redirecting the browser.
Now to my question:
Is it possible with the link (or any other build in-) component to fire requests without redirects? Or do I have to write js by hand? - I know it’s not much work
Is it not very phoneix-ish what I’m doing? I’m almost exclusively worked with django the last years and I guess my structural habits are strong. In a django project I would reach for htmx at this point probably.
Yeah, since you’re already using LiveView based on your last question, you can use a LiveView click event binding to communicate with the server via a lightweight websocket event message rather than a traditional stateless HTTP request.
For a rough mental model, stateful LiveViews replace stateless controllers, websocket events via LiveView bindings replace HTTP requests via AJAX, and LiveView server side handle_event callbacks replace traditional server side controller actions.
That looks like a named slot. It’d be defined by the function component you’re using so search for slot :action or render_slot(@action) in your project.
That looks like a named slot. It’d be defined by the function component you’re using so search for slot :action or render_slot(@action) in your project.
Yeah, since you’re already using LiveView based on your last question, you can use a LiveView click event binding to communicate with the server via a lightweight websocket event message rather than a traditional stateless HTTP request.
That’s what I initially thought, but since I need to update the cart in the session - which is (in it’s default configuration) cookie based - I need a HTTP request cycle.
So my plan looks like this:
Plug initializes the cart within the session and adds an id
I wrap views in a live_session and an on_mount hands on the cart from the session to the socket and
subscribes to a pubsub using the id.
The cart is altered through an extra request to a classic controller that changes the cart in the session and…
Triggers an update of the cart component using the pubsub.
And I’m stuck at step 4 right now. Well, I’m not really stuck, I just want to figure out if I need custom client js code for this, or if I can somehow implement it with build-in tools
I couldn’t figure out, if phoenix has build in components capable of the following, but I found a way to implement the requests to the shopping cart controller that feels kinda idiomatic:
I stumbled across the blog The Pug Automatic from Henrik Nyh where he describes three ways to alter the session when using live views:
As already mentioned, I wanted to follow route three.
Using the according article I figured out, how to implement a custom hook using the LiveView’s JS api by changing the project’s app.js file:
// assets/js/app.js
let Hooks = {};
Hooks.SetSession = {
DEBOUNCE_MS: 200,
// Called when a LiveView is mounted, if it includes an element that uses this hook.
mounted() {
// `this.el` is the form.
this.el.addEventListener("click", (e) => {
clearTimeout(this.timeout);
this.timeout = setTimeout(() => {
// Ajax request to update session.
fetch(this.el.dataset.url, {
method: "post",
headers: {
"x-csrf-token": csrfToken,
},
});
}, this.DEBOUNCE_MS);
});
},
};
// Adopt to include hooks
let liveSocket = new LiveSocket("/live", Socket, {
params: { _csrf_token: csrfToken },
hooks: Hooks,
});
Within the template, I can now use phx-hook to connect the hook with my buttons:
<button
phx-hook="SetSession"
data-url={~p"/cart/add/#{id}"}
id={id}
>
Add to cart
</button>