Slide 40: More Event Examples
"mouseout" is distinguished only as being the last of the three event types to be mentioned within the mybutton list. Let's see what happens when we exchange that line with the line for the "click" type.
Aha; now only the click type has a function associated with it. Those "#event" elements look as if they're contained in a list. List elements are normally separated by a comma (","). Let's try putting a comma at the end of the first two "#event" lines.
Yes! Now we get all three events observed, and the page is working as intended.
Slide 41: More Event Examples
Key takeaway: wf:q(ElementID) lets you process data returned to the Nitrogen server.
Slide 42: Modifying Elements
A few things to note: to make it easier to see what was being replaced, I gave the initial panel some contents like so:
body() ->
#panel { style="margin: 50px", body=[
#button { id=mybutton, text="Submit", postback=click },
#panel { id=placeholder, body=[ #p { body="Text to replace" } ] }
]}.
Another thing: the "click" event can be triggered multiple times; when it does so, the "placeholder" element gets replaced each time - you see the time get changed.
Slide 46: Page State
So: the "body" function generates the page, the "event" functions dictates what the page, in cooperation with the Nitrogen server, will do (which may include changing the page). In this exercise, we want to have a counter start at some value (let's use 0), increment in response to a "click" type event on a "Submit" element, and everything should start over on a page reload.
wf:state_default/2
needs to be called early. I can think of two alternatives: during body generation (so in the
body/0
function), or in an "onpageload" event (I think that's the name; I'll need to look it up). I'll try using
body/0
first.
Here's the first try, which fails when initially trying to generate the page body. The code:
body() ->
wf:state_default(click_counter, 0),
#panel { style="margin: 50px", body=[
#button { id=mybutton, text="Submit", postback=click },
#panel { id=placeholder, body=[ #p { body=io_lib:format("~B", [wf:state(click_counter)]) } ] }
]}.
event(click) ->
wf:state(click_counter, wf:state(click_counter)+1),
wf:update(placeholder, [
#p { body=io_lib:format("~B", [wf:state(click_counter)]) }
]).
...which compiles, but generates this error:
=INFO REPORT==== 15-Jan-2011::13:15:13 ===
{error,error,badarg,
[{io_lib,format,["~B",[undefined]]},
{my_page,body,0},
{element_function,call_next_function,1},
{wf_render_elements,call_element_render,2},
{wf_render_elements,render_element,1},
{wf_render_elements,render_elements,2},
{lists,foldl,3},
{wf_render_elements,render_elements,2}]}
If I replace the initial value reference,
wf:state('click_counter')
with the constant 0, the page renders, but it doesn't update. The page source shows a script that looks like it fires, but the only effect is to generate this message in the Firefox console:
Warning: Unknown pseudo-class or pseudo-element 'input'.
Source File: http://localhost:8000/my/page
Line: 0
Quick research into the "onpageload" event shows that it's different between IE and everyone else (IE:
document.attachEvent('onload',startClock);
; everyone else:
document.addEventListener('load',startClock,false);
). That looks like a dead end.
OK, I give up.
Slide 47: Page State (answer to exercise)
O.K. So
wf:state_default/2
doesn't work at all as I imagined. Instead, if the atom's state is not defined by the page, it returns the default, and if it
is defined by the page it returns that value. I like this minor variant on their answer better:
body() ->
#panel { style="margin: 50px", body=[
#button { id=mybutton, text="Submit", postback=click },
#panel { id=placeholder, body="0" }
]}.
event(click) ->
Counter = wf:state_default(click_counter, 0) + 1,
wf:update(placeholder, [
#panel { body=wf:f("~B", [Counter]) }
]),
wf:state(click_counter, Counter).
It appears that the Firefox console complaint is "normal" - the page is working as expected, but the complaint still occurs.