0 books found

Explanation

This demo illustrates the power of combining Stimulus with StimulusReflex. It leverages Stimulus to provide feedback. We debounce with with the prefix debounced: provided by a npm package (so we don't DOS the API).

Code (56 LOC)

ERB (37 LOC)
app/views/book_searches/_demo.html.erb (37 LOC)
<div data-controller="book-search" data-reflex-root="#morph">
<input type="text" placeholder="Search for a book..." class="form-control form-control-lg d-inline-block col-4"
data-target="book-search.query" data-action="debounced:input->book-search#perform">
<div id="morph" class="mt-4">
<span data-target="book-search.activity" class="text-danger" hidden>
<i class="fas fa-spinner fa-spin"></i>
Searching for books...
</span>
<span data-target="book-search.count" class="text-success">
<strong><%= number_with_delimiter @books&.dig("num_found").to_i %></strong> books found
</span>
<table data-target="book-search.list" class="table mt-2" <%= "hidden" unless @books&.dig("docs").present? %>>
<thead>
<tr>
<th scope="col">Subject</th>
<th scope="col">Title</th>
<th scope="col">Author</th>
<th scope="col">Publish Date</th>
<th scope="col">ISBN</th>
</tr>
</thead>
<tbody>
<% if @books&.dig("docs").present? %>
<% @books["docs"][0,12].each do |book| %>
<tr>
<td><%= truncate book["subject"]&.join(", "), length: 30 %></th>
<td><%= truncate book["title"], length: 30 %></th>
<td><%= book["author_name"]&.join ", " %></td>
<td><%= book["first_publish_year"] %></td>
<td><%= book["isbn"]&.first %></td>
</tr>
<% end %>
<% end %>
</tbody>
</table>
</div>
</div>
JavaScript (12 LOC)
app/javascript/controllers/book_search_controller.js (12 LOC)
import ApplicationController from './application_controller'
export default class extends ApplicationController {
static targets = ['query', 'activity', 'count', 'list']
beforePerform (element, reflex) {
this.activityTarget.hidden = false
this.countTarget.hidden = true
}
perform (event) {
event.preventDefault()
this.stimulate('BookSearchReflex#perform', this.queryTarget.value)
}
}
Ruby (7 LOC)
app/reflexes/book_search_reflex.rb (7 LOC)
class BookSearchReflex < ApplicationReflex
def perform(query = "")
return unless query.size > 2
result = HTTP.get("http://openlibrary.org/search.json?#{{q: query}.to_query}")
@books = JSON.parse(result.to_s) if result.status == 200
end
end