Stimulus async load Rails HTML - `Rails.ajax` the RJS (format.js) way (full)
Today I've Learned postor: How to load Rails HTML content with Stimulus JS using good old Rails format.js, .js.erb files without any JSON woodoo or: Stimulous with SJR (Server-Generated Javascript)
This is subarticle of Stimulus JS Cheat Sheet
I also wrote Rails.ajax
the render_to_string
way (so exact oposit of this solution)
Rails stuff
# config/routes.rb
# ...
resources :entries_search, only: [] do
post :load_sub_category, on: :collection
end
# ...
# /app/controllers/entries_search_controller.rb
class EntriesSearchController < ApplicationController
def load_sub_category
@main_category = Category.find(params[:main_category_id])
respond_to do |format|
format.js { render 'load_sub_category' }
end
end
end
-# /app/views/entries_search/index.html.slim
div data-controller="entries-search" data-entries-search-categories-load-path="#{load_sub_categories_entries_search_index_path}"
#sub-categories
-# here the response will get loaded
.chip.hoverable data-action="click->entries-search#loadSubCategories" data-main-category-id="123"
| Load "Puppies" Sub Categories
.chip.hoverable data-action="click->entries-search#loadSubCategories" data-main-category-id="345"
| Load "Kittens" Sub Categories
note:
load_sub_categories_entries_search_index_path
is being translated to/entries_search/load_sub_categories
by Rails routes
-# /app/views/entries_search/_categories.html.slim
- main_category.sub_categories.each do |sub_category|
.chip= sub_category.title
// /app/views/entries_search/load_sub_categories.js.erb
if @main_category
$('#sub-categories').html("<%= j(render('entries_search/categories', locals: { main_category: @main_category})) %>");
else
alert('Error: no Category match this ID');
end
JS stuff
//package.json
{
"dependencies": {
# ...
"@rails/ujs": "^6.0.0-alpha",
"stimulus": "^1.1.1",
# ...
}
}
import { Controller } from "stimulus"
import Rails from "@rails/ujs";
export default class extends Controller {
loadSubCategories(e) {
let categoriesLoadPath = this.data.get('categories-load-path');
let mainCategoryId = e.currentTarget.dataset.mainCategoryId;
Rails.ajax({
type: "post",
dataType: 'script',
url: categoriesLoadPath,
data: `main_category_id=${mainCategoryId}&location=Slovakia`,
})
}
}
Note how in Rails.ajax
we don’t do the success:
or error:
parts.
With RJS the success / error is being handled by the JS response comming from Rails controller response.
e.g. if there is success .js.erb
file relpace the HTML content of element with
independent JS execution outside Stimulous controller. Same apply for errors response.
Stringify query
as you may notice Rails.ajax
is using stringified query as the data
parameter
if you want to stringify the query from hash object, with IE6 you can do:
import { Controller } from "stimulus"
import Rails from "@rails/ujs";
const querystring = require('querystring');
export default class extends Controller {
loadSubCategories(e) {
let data = {chip_type: 'category', chip_id: 1234}
let queryStr = querystring.stringify(data) // chip_type=category&chip_id=1234
Rails.ajax({
type: "post",
dataType: 'script',
url: categoriesLoadPath,
data: queryStr
})
}
}
Other sources
Entire blog website and all the articles can be forked from this Github Repo