How to create UI components

The page describes how to create a new UI component.

A fully functional example of source code you can find here

Steps

Create a component class

Create a class inherited fromApplicationComponentunderapp/components/. By convention a class for a component must end in "Component". Add#initializemethod to the class.

    def initialize(template, model)
      super template

      @model = model
    end

Tips

  • It is better if namespaces of a component and a related controller are similar. It is not required but it simplifies stuff.

  • it is encouraged to create a related presenter class as a counterpart of a UI component. In this case a presenter is responsible for fetching data, including optimization concerns. At the same moment a component is responsible for: 1) rendering data, including formatting 2) handling details of WEB UI (for example how to translate names of request params to attributes of a presenter)

Example: component class

Create a view partial for a component

Create a partial file (/^_*.html.erb$/) underapp/views/components. A file-path to just created view have to mimic namespacing of the component. For example if we haveFoo::Bar::BazComponent, we have to createapp/views/components/foo/bar/_baz.html.erb.

Example:partial

Instantiate a component object

Instantiate a component object usingApplicationController#new_componentmethod:

  @baz = new_component(::Foo::Bar::BazComponent, @some_presenter)

Example: instantiation

Call #render

Render your component using inherited#rendermethod:

<%= @baz.render %>

Example: call render

Add JavaScript support (optional)

If your component depends on JS functionality, you should perform a few additional steps.

MixJsAwaremodule to your component.

module Foo
  module Bar
    class BazComponent < ApplicationComponent
      include JsAware
      ...

Create JS file underapp/javascripts/main/components/using the same approach to "namespacing" like for the view partial:app/javascripts/main/components/foo/bar/baz.js

A javascript object for a component should haveinitmethod. Th method is call right after component is rendered.

window.foo = window.foo || {}
window.foo.bar = window.foo.bar || {}

window.foo.bar.Baz = (function () {
  var c = {};

  c.init = function (_opts) {
    $('.baz-time').html(new Date().toString())
  }

  return c;
})();

Add newly created JS file to grunt.js. It is preferable to use wildcards:

'app/javascripts/main/components/foo/bar/*.js'

Recompile javascript (rungruntconsole command).

Example: js file

Basically that's it. We just created a new UI component.

Last updated