HTML Over the Wire
But what if we didn’t send JSON over the wire? What if there was a way to send HTML over the wire, and make it look sexy? One of the advantages of SPAs is that they can update part of a page, rather than the entire page.
Let’s consider a scenario : we have a tabular display, and the user wants to apply some filters. Using the SPA approach, we would send all the data for the display as JSON to the client browser. The JS would then apply the filters, and refresh the view.
Instead, if we are using the server to apply the filter, the client would make a request to the server with the filter parameters. The server would fulfill this request by sending an HTML response to the client browser. The client browser would refresh the page, and the user would see the filtered table.
There are a couple disadvantages to this approach. First, the page refresh is not ideal. It adds loading time to the UX, and can cause the user to lose their place if the entire page is reloaded. And if we only want to change one part of the page, it does not make sense to reload the entire page if we can avoid it.
So, how can we reload part of a page while still using the server to apply our filter?
Turbo is one of the frontend frameworks supplied as part of the Hotwired kit. Per their website - Turbo Frames allow predefined parts of a page to be updated on request. So if you want to apply a filter and update a table, you can define the table within a Turbo Frame. When the user applies a filter by clicking a button, the browser makes a request to the server. The response is used to populate the HTML within the Turbo Frame. Nothing changes outside the Turbo Frame.
In the example below, I use ERB to iterate through the instance variable
@users. The example will look familiar if you use Rails, however, this example applies to any backend framework.
<turbo-frame id="users"> <table> <thead> <tr> <th>Name</th> <th>Email</th> </tr> </thead> <tbody> <% @users.each do |user| %> <tr> <td> <p> <%= user.name %> </p> </td> <td> <p> <%= user.email %> </p> </td> </tr> <% end %> </tbody> </table> </turbo-frame>
Now, let’s say we want to add a text search. We can add a form with an
input element, which submits a request to the appropriate HTTP method. We want to add this form within the existing
turbo-frame so that the results of the request will be used to replace the contents of that frame.
<turbo-frame id="users"> <form action="/sort_users" data-turbo-frame="users"> <input name="query"> <button>Search</button> </form> ... </turbo-frame>
When the user types a name in the input and clicks Search, a request will be submitted to the path
sort_users. The server will handle the request, parse the parameters and respond with HTML. Turbo will intercept this HTML and use it to populate the
turbo-frame element with the
In the case that you can live with the server/client latency, this method provides an alternative way to modify the display without using the client browser to generate HTML. In some cases, this will be cleaner and easier to implement than implementing a SPA framework in the browser.