How does one make a like/unlike function with stimulus? I read the old school way of doing this is to create a create.js.erb file that renders a view page. I’m fairly new to Javascript so explain it like how you’d explain it to a 10 yr old. thanks
If you need the server to validate that the like/unlike happened, it’s still perfectly fine to use a *.js.erb
response to insert the updated button.
You’re not using a MVC framework like Vue or React, so you’ll end up handling some server-generated content yourself either way
One way of handling it with Stimulus is to catch the server-rendered content in an action responsible for updating the button.
Imagine the following button somewhere on your page:
# app/views/likes/_like.html.erb
<%= button_to 'Like', post_likes_path(@post), method: :post, remote: true, data: { action: 'ajax:success->like#updateButton' } %>
When the button is pressed, the request is handled by the LikesController
:
# app/controllers/likes_controller.rb
class LikesController < ApplicationController
def create
@like = @post.likes.create
render partial: 'unlike'
end
def destroy
@like.destroy
render partial: 'like'
end
end
It creates the like and renders a partial containing the toggled button
# app/views/likes/_unlike.html.erb
<%= button_to 'Unlike', post_like_path(@post, @like), method: :delete, data: { action: 'ajax:success->like#updateButton' } %>
The browser itself doesn’t know what to do with the piece of server-generated HTML, but our Stimulus controller handles the event due to the ajax:success
event listener attached to the button.
It replaces the button inside the controller action like this:
// app/javascript/packs/controllers/like_controller.js
export default class extends Controller {
updateButton(event) {
let [data, status, xhr] = event.detail;
this.currentTarget.replaceWith(xhr.response);
}
}
Note that the function
ChildNode.replaceWith()
is experimental and might not work in all browsers: Element: replaceWith() method - Web APIs | MDN
While it’s absolutely possible to handle a case like this with Stimulus, I’m not sure I’d call this a win, compared to just replacing the button directly with a JavaScript response:
# app/views/likes/create.js.erb
document.getElementById("<%= dom_id(@like) %>").replaceWith("<%= j render partial: 'unlike' %>")
I hope this helped a bit
This reply is a win! Thank you, you kind soul. I was looking at how instagram built heart like button in a stimulus way. I’ve heard much praise from this framework so i decided to try, before this i was on that vanilla/coffee/jquery thing and that was confusing
You’re welcome! Stimulus is really well suited for progressively enhancing you app with JavaScript in the places where you need it. It doesn’t take over your entire front-end, which is also why you have to handle things such as requesting/receiving data from a server yourself.
Personally I think it’s great. It’s one of the least invasive JavaScript frameworks out there It fits well into existing application and it’s easy to get started with, because there are relatively few concepts to grasp.