Posts Tagged ‘Events’

Acting upon clicks in an ExtJS TreePanel

Tuesday, June 10th, 2008

ExtJS’ TreePanel absolutely rock. You can display complicated data structures without worrying about the rendering process at all. However, what if you want to catch a click on a node and somehow process it in the Apotomo/Ruby environment?

In this example I’ll attach an event handler to a TreePanel which updates another widget whenever a node is clicked.

First we’ll have a look at the WidgetTree setup.

app/apotomo/apotomo_widget_tree.rb

1
2
3
4
5
6
7
8
9
10
ts = Apotomo::TreeStore.new
ts[:root] = {:two=>{:two_one=>{}}, :three=>{}}
 
w << pnl = ext_panel('big_panel', :title => "Big Panel")
  pnl << tpanel = ext_tree_panel('an_ext_tree', :width => 200)    
    tpanel.set_store(ts)
 
  pnl << peer_panel = ext_panel('peer_panel', :title => "Tree peer", :width => 300)
    peer_panel << cell(:tree_peer, :init, 'my_tree_peer')
      tpanel.watch(:click, 'my_tree_peer', :_show_clicked)

When rendered, this leads to the following app state.

We can see the TreePanel widget and the “Peer Panel” widget being pushed into the “Big Panel” (line 5 and 8).

The my_tree_peer widget is in state :init, displaying a message that nothing special happened (line 9). If a click in the tree is encountered, my_tree_code is asked to go into the state :_show_clicked. (line 10).

Let’s click on a node.

In our new application state, the my_tree_peer widget reports which node was clicked. How spectacular! The Apotomo event dispatcher sent it to another state. We can find out how this new state works by looking at the widget code.

app/cells/tree_peer_cell.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class TreePeerCell < Apotomo::StatefulWidget
 
  def transition_map
    { :init => [:_show_clicked],
      :_show_clicked => [:_show_clicked],
    }
  end
 
  def init
    "No item has been clicked."
  end
 
  def _show_clicked
    node_id = param(:node_id)
    "You clicked node #{node_id}."
  end
 
end

The two state methods just send static html to the screen, which is ok for demonstration purposes.

Note how we mapped a real ExtJS client-side event into a server-side Ruby event and managed all the event-handling in pure ruby. That’s Apotomo!

Observing a form

Sunday, May 18th, 2008

Apotomo introduces an event-driven approach for Rails applications. Some widgets fire events, other register handlers for these events. I’ll demonstrate this with an example, where one small widget observes a form and acts upon a certain event from this form.

Taking our simple form example, I add one line to the form processing state.

app/cells/simple_form_cell.rb

14
15
16
17
18
19
20
  def _process_form
    res = @user.update_attributes(param(:user))
    return state_view :form unless res
 
    trigger(:userCreated)
    state_view :user_created
  end

Easy: if the user can successfully be created, the form widget informs all other (interested!) widgets about this spectacular incident by triggering a generic :userCreated event (line 18).
That’s all for this form widget. It no longer is actively involved in the following steps.

The Observer
Another widget is interested in that user creation and registers an observer for that.

app/cells/form_observer_cell.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class FormObserverCell < Apotomo::StatefulWidget
  def transition_map
    { :lurk => [:_observe_form]
    }
  end
 
  def lurk
    "lurking..."
  end
 
  def _observe_form
    "I smell a userCreated event!"
  end
end

Normally the widgets lurks around in the state :lurk. When the :userCreated event is fired, it wants itself to go into the state :_observe_form. How to do that?
A common place to attach observers is the application widget tree. I love this word.

app/apotomo/application_widget_tree.rb

  playgrd << simple_form = cell(:simple_form, :form, 'simple_form')
 
  playgrd << cell(:form_observer, :lurk, 'form_observer')
  simple_form.watch(:userCreated, 'form_observer', :_observe_form)

I first add the simple_form widget to the page. Then the form_observer widget with start state :lurk.

The watch call attaches the observer to simple_form, instructing the event system to invoke :_observe_form on the widget form_observer whenever an userCreated event is triggered.
This sounds confusing but it makes sense. In GUI architectures, it is common to attach callbacks as event handlers - in our case, we assigned a state method of a widget as an event handler.