Ovto::Component

An Ovto app must have MainComponent class, a subclass of Ovto::Component.

'render' method

render is the only method you need to define in the MainComponent class. You can get the global app state by calling state method.

  class MainComponent < Ovto::Component
    def render
      o 'div' do
        o 'h1', 'Your todos'
        o 'ul' do
          state.todos.each do |todo|
            o 'li', todo.title
          end
        end
      end
    end
  end

MoreThanOneNode error

If you missed the surrounding 'div' tag, Ovto raises an MoreThanOneNode error. render must create a single DOM node.

    def render
      o 'h1', 'Your todos'
      o 'ul' do
        state.todos.each do |todo|
          o 'li', todo.title
        end
      end
    end

#=> $MoreThanOneNode {name: "MoreThanOneNode", ...}

The 'o' method

Ovto::Component#o describes your app's view. For example:

o 'div'
#=> <div></div>

o 'div', 'Hello.'
#=> <div>Hello.</div>

You can pass attributes with a Hash.

o 'div', class: 'main', 'Hello.'
#=> <div class='main'>Hello.</div>

There are shorthand notations for classes and ids.

o 'div.main'
#=> <div class='main'>Hello.</div>

o 'div#main'
#=> <div id='main'>Hello.</div>

You can also give a block to specify its content.

o 'div' do
  'Hello.'
end
#=> <div>Hello.</div>

o 'div' do
  o 'h1', 'Hello.'
end
#=> <div><h1>Hello.</h1></div>

Special attribute: style

There are some special keys for the attributes Hash. style: key takes a hash as its value and specifies styles of the tag.

o 'div', style: {color: 'red'}, 'Hello.'
#=> <div style='color: red;'>Hello.</div>

Special attribute: onxx

An attribute starts with "on" specifies an event handler.

For example:

o 'input', {
  type: 'button',
  onclick: ->(e){ p e.target.value },
  value: 'Hello.'
}

The argument e is an instance of Opal::Native and wraps the JavaScript event object. You can get the input value with e.target.value here.

Lifecycle events

There are special events oncreate, onupdate, onremove, ondestroy.

https://github.com/hyperapp/hyperapp#lifecycle-events

Special attribute: key

https://github.com/hyperapp/hyperapp#keys

Sub components

o can take another component class to render.

  # Sub component
  class TodoList < Ovto::Component
    def render(todos:)
      o 'ul' do
        todos.each do |todo|
          o 'li', todo.title
        end
      end
    end
  end

  # Main component
  class MainComponent < Ovto::Component
    def render
      o 'div' do
        o 'h1', 'Your todos'
        o TodoList, todos: state.todos
      end
    end
  end

Text node

Sometimes you may want to create a text node.

#=> <div>Age: <span class='age'>12</a></div>
#        ~~~~~
#          |
#          +--Raw text (not enclosed by an inner tag)

o generates a text node when 'text' is specified as tag name. The above HTML could be described like this.

o 'div' do
  o 'text', 'Age:'
  o 'span', '12'
end