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_stringway (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_pathis being translated to/entries_search/load_sub_categoriesby 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