My first use-case for stimulus is refactoring a bookmarking feature on a products page where the whole product list (and most of the page) is cached server side with Russian Doll caching. So, we can’t just use inline data maps for the initial page state to indicate a user has bookmarked a product on initial load.
Previously, we had put the state of a users’ bookmark for a product in data attributes of a div just outside the products’ top-level cache statement. Then after page load, we had a bit of procedural-style jQuery that would read the special div’s data attrs and render the correct bookmark state, as well as bookmark toggle code that watches for a click, displays a spinner, and then applies the new state.
I feel like this is exactly what stimulus is made to clean up, but I’m not sure what to do with the initial page state, since it can’t be applied inline to the bookmarks HTML.
Obviously I could just keep doing what I’m doing, and read the state off a special div’s data attrs. Is there a more idiomatic way though, along the lines of data maps? “Remote data maps” or something?
Here’s an extremely simplified example.
Previously
HTML:
<div class="js-bookmark-state" data-bookmarked-products="123,456,789" />
<% cache do %>
<% @products.each do |product| %>
<div class="product" id="product-<%= product.id %>">
<div class="product-name"><%= product.name %>
<button class="bookmark-btn" data-bookmark-url="/path/to/bookmark" />
<span class="bookmark-active fa fa-bookmark" style="display: none" />
<span class="bookmark-inactive fa fa-bookmark-o" style="display: none" />
</div>
</div>
<% end %>
<% end %>
JS:
Something that reads ‘js-bookmark-state’ to create a bookmarkedProducts
array, then finds the correct bookmarked products and calls $.show()
on the correct icon.
Also, watches for clicks on .bookmark-btn
, and reads the response to similarly call $.toggle()
on the icons if successful.
Now, using stimulus:
<% cache do %>
<% @products.each do |product| %>
<div class="product" id="product-<%= product.id %>">
<div class="product-name"><%= product.name %>
<button class="bookmark-btn" data-controller="bookmark" data-bookmark-url="/path/to/bookmark" data-program-id="<%= product.id %> />
<span class="bookmark-active fa fa-bookmark" style="display: none" />
<span class="bookmark-inactive fa fa-bookmark-o" style="display: none" />
</div>
</div>
<% end %>
<% end %>
The stimulus Bookmark
instance can know the program-id
via data maps, but is the best way to track bookmarked programs via a special div?