+++ title = "Advanced Nitrogen Elements" date = 2009-06-16T23:33:58Z in_search_index = true [taxonomies] tags = [ "Site-News", "erlang", "javascript", "nitrogen", "tutorial", "web-framework", ] +++ In my last post I walked you through creating a basic nitrogen element. In this one I'll be covering some of the more advanced topics in nitrogen elements.
% given this event
#event{ type=click, postback={click, Id} }
% this event function would handle it
event({click, ClickedId}) ->
io:format("I [~p] was clicked", [ClickedId]) .
Erlangs pattern matching makes it especially well suited for this kind of event based programming. The one annoying limitation of this event though is that each page has to handle it individually. You could of course create a dispatching module that handled the event for you but why when nitrogen already did it for you. You can delegate an event to a specific module by setting the delegate attribute to the atom identifying that module.
% delgated event
#event{ type=click, postback={click, Id}, delegate=my_module }
You can delgate to any module you want. I use the general rule of thumb that if the event affects other elements on the page then the page module should probably handle it. If, however, the event doesn't affect other elements on the page then the element's module can handle it.
-record(silly, {?ELEMENT_BASE(element_silly)}).
And the module is likewise simple:
-module(element_silly).
-compile(export_all).
-include("elements.hrl").
-include_lib("nitrogen/include/wf.inc").
render(ControlId, R) ->
Id = wf:temp_id(),
%% wait!! where do we get the loc from?!
ClickEvent = #event{type=click, postback={click, Loc}}
Panel = #panel{id=Id, style="width:'100px' height='100px'",
actions=ClickEvent}, element_panel:render(Panel).
event({click, Loc}) ->
wf:update(body, wf:f("you clicked at point = "~s", Loc))."
Well of course you spot the problem here. Since the click happens client side we don't know what to put in the Loc variable for the postback. A typical postback won't work because the data will be generated in the client and not the Nitrogen server. So how could we get the value of the coordinates sent back? The javascript to grab the coordinates with jquery looks like this = ""
var coord = obj('me').pageX + obj('me').pageY;
To plug that in to the click event is pretty easy since action fields in an event can hold other events or javascript or a list combining both:
Script = "var coord = obj('me').pageX + obj('me').pageY;",
ClickEvent = #event{type=click, postback={click, Loc}, actions=Script}
Now we've managed to capture the coordinates of the mouse click, but we still haven't sent it back to the server. This javascript needs a little help. What we need is a drop box. Lets enhance our element with a few helpers:
-module(element_silly).
-compile(export_all).
-include("elements.hrl").
-include_lib("nitrogen/include/wf.inc").
render(ControlId, R) ->
Id = wf:temp_id(),
DropBoxId = wf:temp_id(),
MsgId = wf:temp_id(),
Script = wf:f("var coord = obj('me').pageX + obj('me').pageY; $('~s').value = coord;",
[DropBoxId]),
ClickEvent = #event{type=click, postback={click, Id, MsgId},
actions=Script},
Panel = #panel{id=Id, style="width:'100px'; height='100px'",
actions=ClickEvent, body=[#hidden{id=DropBoxId},
#panel{id=MsgId}]},
element_panel:render(Panel).
event({click, Id, Msg}) ->
Loc = hd(wf:q(Id)),
wf:update(Msg, wf:f("you clicked at point = "~s", Loc))."
Ahhh there we go. Now our element when clicked will: