stimulus
Write Stimulus controllers in Crystal. Based on js.cr, designed for compatibility with to_html.cr.
Installation
- 
Add the dependency to your shard.yml:dependencies: stimulus: github: sbsoftware/stimulus.cr
- 
Run shards install
Usage
require "stimulus"Defining Controllers
You can define values and targets once. As Stimulus::Controllers are just JS::Classes, you can add js_methods as much as you want - but if you want to reference them as controller actions in your Crystal code or templates, use the action macro.
class LogController < Stimulus::Controller
  values message: String, css_class: String
  targets :element
  js_method :connect do
    console.log(this.messageValue)
  end
  action :do_it do
    this.elementTarget.classList.toggle(this.cssClassValue)
  end
endOutlets
The outlets macro expects a list of other Stimulus::Controllers and provides you a method for each to define the outlet in your template.
class SomeController < Stimulus::Controller
  action :do_some do
    console.log("Something!")
  end
end
class OtherController < Stimulus::Controller
end
class MyController < Stimulus::Controller
  outlets SomeController, OtherController
  action :do_it do
    this.someOutlet.do_some._call
  end
end
class MyView
  ToHtml.class_template do
    div SomeController, id: "some_id"
    div MyController, MyController.some_controller_outlet("#some_id"), MyController.do_it_action("click") do
      "Click me!"
    end
  end
endPrinting Controllers
Just use .to_js to print the JS code of your controller where your want to have it.
<html>
  <head>
    <script>
      <%= LogController.to_js %>
    </script>
  </head>
</html>Referencing Controllers
All your values, targets and actions can be referenced via class methods of the controller. Their #to_s methods present them as the HTML attribute strings they need to be:
<div <%= LogController %> <%= LogController.message_value("Hello World!") <%= LogController.css_class_value("my_class") %>>
  <div <%= LogController.element_target %>>Test!</div>
  <div <%= LogController.do_it_action("click") %>>Go!</div>
</div>=>
<div data-controller="log" data-log-message-value="Hello World!" data-log-css-class-value="my_class">
  <div data-log-target="element">Test!</div>
  <div data-action="click->log#do_it">Go!</div>
</div>
  
Compatibility with to_html.cr
When using to_html.cr, things get even more comfortable. The controller and its value, target or action objects know how to fit into an HTML element as an attribute. The to_html attribute interface even manages adding multiple controllers/values/targets/actions to the same element, which would be cumbersome with plain ECR.
div LogController, LogController.message_value("Hello World!"), LogController.css_class_value("my-class") do
  div LogController.element_target do
    "Test!"
  end
  div LogController.do_it_action("click") do
    "Go!"
  end
end