Skip to content

Instantly share code, notes, and snippets.

@tdak
Created November 10, 2020 13:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tdak/fa9e67bba77f418e6b66b055492d188d to your computer and use it in GitHub Desktop.
Save tdak/fa9e67bba77f418e6b66b055492d188d to your computer and use it in GitHub Desktop.
Reactive Ajax Components for Rails
<div>
<%= project.name %>
</div>
export class AjaxComponent {
constructor(componentLoadEvent="component:load", componentTag="ajax-component") {
this.pageReadyEvent = "turbolinks:load" //"DOMContentLoaded"
this.componentLoadEvent = componentLoadEvent
this.componentTag = componentTag
this.loadComponentDataSelector = "data-load-component"
this.splitter = "->"
}
preloadComponents(preloadAttribute="preload") {
const selector = this.componentTag + "[" + preloadAttribute + "]"
document.querySelectorAll(selector).forEach(function(item, index) {
updateAjaxComponent(item.getAttribute("id"), false)
})
}
setupComponentLoadTriggers(callback){
var selector = "[" + this.loadComponentDataSelector + "]"
var instance = this;
document.querySelectorAll(selector).forEach(function(item, index) {
var triggers = item.getAttribute(instance.loadComponentDataSelector).split(instance.splitter)
item.removeEventListener(triggers[0], callback)
item.addEventListener(triggers[0], callback)
})
}
updateAjaxComponent(e_id, broadcastToChannel = false) {
var element = document.getElementById(e_id)
if (!element) {
return
}
var url = element.getAttribute("src")
var method = element.getAttribute("method")
var instance = this
if (!method) { method = "GET" }
Rails.ajax({
type: method,
url: url,
beforeSend: function( xhr ) {
xhr.setRequestHeader('Accept', 'text/ajax-component, */*')
return true
},
complete: function(xhr, status) {
// update html
element.innerHTML = xhr.responseText
// if there are script tags, evaluate them by adding to head and removing it
instance.evaluateScriptTags(element)
Rails.fire(document, instance.componentLoadEvent)
if (broadcastToChannel){
// we're gonna broadcast to channel
}
}
})
}
evaluateScriptTags(element) {
var scriptElements = element.getElementsByTagName('SCRIPT');
for (var i = 0; i < scriptElements.length; i ++) {
var scriptElement = document.createElement('SCRIPT');
scriptElement.type = 'text/javascript';
if (!scriptElements[i].src) {
scriptElement.innerHTML = scriptElements[i].innerHTML;
} else {
scriptElement.src = scriptElements[i].src;
}
document.head.appendChild(scriptElement).parentNode.removeChild(script)
}
}
}
<%= render @projects %>
<ajax-component id="projects_list" src="<%= projects_path %>" preload="true"></ajax-component>
import { AjaxComponent } from "./ajax_component"
window.ajax_updater = new AjaxComponent()
// CALL BACKS
window.ajaxUpdaterUpdateComponent = function(e) {
var triggers = this.getAttribute(ajax_updater.loadComponentDataSelector).split(ajax_updater.splitter);
ajax_updater.updateAjaxComponent(triggers[1])
}
window.ajaxUpdaterSetupEventTriggers = function() {
ajax_updater.setupComponentLoadTriggers(ajaxUpdaterUpdateComponent)
}
window.ajaxUpdaterPreloadComponents = function() {
ajax_updater.preloadComponents()
}
window.updateAjaxComponent = function(element_id, broadcastToChannel = false) {
ajax_updater.updateAjaxComponent(element_id, broadcastToChannel)
}
// LISTENERS
document.addEventListener(ajax_updater.pageReadyEvent, ajaxUpdaterPreloadComponents)
document.addEventListener(ajax_updater.componentLoadEvent, ajaxUpdaterSetupEventTriggers)
updateAjaxComponet("projects_list")
Mime::Type.register "text/ajax-component", :component
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment