diff --git a/content/Advanced-Nitrogen-Elements-2009-6-16.md b/content/Advanced-Nitrogen-Elements-2009-6-16.md index 4afb7f2..11a7308 100644 --- a/content/Advanced-Nitrogen-Elements-2009-6-16.md +++ b/content/Advanced-Nitrogen-Elements-2009-6-16.md @@ -13,20 +13,25 @@ tags = [ ] +++ 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.
+
+````erlang
% 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.
-
+
+```erlang
% 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.
+
+```erlang
-record(silly, {?ELEMENT_BASE(element_silly)}).
And the module is likewise simple:
@@ -46,13 +51,18 @@ event({click, 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:
-
+```
+
+ 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:
+
+```erlang
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:
-
+
+```erlang
-module(element_silly).
-compile(export_all).
-include("elements.hrl").
@@ -73,5 +83,8 @@ render(ControlId, R) ->
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: + +```erlang %Put this line in an include file for your elements -record(notify, {?ELEMENT_BASE(element_notify), expire=false, msg}). --
+``` + +```erlang % put these at the top of your elements module -include_lib("nitrogen/include/wf.inc"). % the above mentioned include file you may call it whatever you want -include("elements.inc"). -+``` + The ELEMENT_BASE macro gives your element several fields and identifies for the element which module handles the rendering of your nitrogen element. You can specify any module you want but the convention is to name the module with element_element_name. The fields provided are: id, class, style, actions, and show_if. You can use them as you wish when it comes time to render your element. Which brings us to the module.
+ +```erlang -module(element_notify). -compile(export_all). -include_lib("nitrogen/include/wf.inc"). @@ -46,27 +50,35 @@ render(ControlId, R) -> % Or use the alternative method: Module = Panel#panel.module, Module:render(Id, Panel). -+``` + Notice that the records module attribute tells us what module we should call to render the element in the alternative method. In our case we will just hardcode the module since it's known to us. So now we have a basic element that renders a div with a temp id to our page. That's not terribly useful though. We actually need this element to render our msg, and with some events attached. Lets add the code to add our message to the panels contents. -
+ +```erlang Panel = #panel{id=Id, body=R#notify.msg}, element_panel:render(ControlId, Panel) -+``` + Now whatever is in the msg attribute of our notify record will be in the body of the panel when it gets rendered. All we need is a way to dismiss it. A link should do the trick. But now we have a slight problem. In order to add our dismiss link we need to add it to the body of the Panel. but the msg is already occupying that space. We could use a list and prepend the link to the end of the list for the body but that doesn't really give us a lot of control over styling the element. what we really need is for the msg to be in an inner panel and the outer panel will hold any controls the element needs. -
+ +```erlang Link = #link{text="dismiss"}, InnerPanel = #panel{body=R#notify.msg}, Panel = #panel{id=Id, body=[InnerPanel,Link]}, element_panel:render(ControlId, Panel) -+``` + Our link doesn't actually dismiss the notification yet though. To add that we need to add a click event to the link. Nitrogen has a large set of events and effects available. You can find them . We will be using the click event and the hide effect. -
+ +```erlang Event = #event{type=click, actions=#hide{effect=blind, target=Id}}, Link = #link{text="dismiss", actions=Event}, -+``` + Now our module should look something like this: -
+ +```erlang -module(element_notify). -compile(export_all). -include_lib("nitrogen/include/wf.inc"). @@ -85,9 +97,12 @@ render(ControlId, R) -> Panel = #panel{id=Id, body=[InnerPanel,Link]}, % the element_panel module is used to render the panel element element_panel:render(Id, Panel). -+``` + This is a fully functional nitrogen element. But it's missing a crucial feature to really shine. Our third feature for this element was an optional expiration for the notification. Right now you have to click dismiss to get rid of the element on the page. But sometimes we might want the element to go away after a predetermined time. This is what our expire record field is meant to determine for us. There are three possible cases for this field.
+ + +```erlang case R#notify.expire of false -> undefined; @@ -98,9 +113,11 @@ case R#notify.expire of % log error and don't expire undefined end -+``` + Notice the wf:wire statement. wf:wire is an alternate way to add events to a nitrogen element. Just specify the id and then the event record/javascript string you want to use. I've noticed that for events of type timer wf:wire works better than assigning them to the actions field of the event record. No idea why because I have not looked into it real closely yet. Now our module looks like this: -
+ +```erlang -module(element_notify). -compile(export_all). -include_lib("nitrogen/include/wf.inc"). @@ -129,14 +146,18 @@ render(_, R) -> Panel = #panel{id=Id, body=[InnerPanel,Link]}, % the element_panel module is used to render the panel element element_panel:render(ControlId, Panel). -+``` + We have now fulfilled all of our criteria for the element. It shows a message of our choosing. It can be dismissed with a click. And it has an optional expiration. One last thing to really polish it off though would to allow styling through the use of css classes. The ELEMENT_BASE macro we used in our record definition gives our element a class field. We can use that to set our Panel's class, allowing any user of the element to set the class as they wish like so: -
+ +```erlang Panel = #panel{id=Id, class=["notify ", R#notify.class], body=[InnerPanel,Link]}, -+``` + This gives us the final module for our custom element: -
+ +```erlang -module(element_notify). -compile(export_all). -include_lib("nitrogen/include/wf.inc"). @@ -166,5 +187,6 @@ reflect() -> record_info(fields, notify). body=[InnerPanel,Link]}, % the element_panel module is used to render the panel element element_panel:render(ControlId, Panel). -+``` + I will cover delegated events and more advanced topics in a later tutorial. diff --git a/content/First-Look-at-Polymer-Elements-2013-09-17.md b/content/First-Look-at-Polymer-Elements-2013-09-17.md index 18972a1..b43a2e6 100755 --- a/content/First-Look-at-Polymer-Elements-2013-09-17.md +++ b/content/First-Look-at-Polymer-Elements-2013-09-17.md @@ -27,7 +27,7 @@ For my purposes I ported the DynamicBible search box and a requirejs importer el Creating your own Polymer Element ================================= -``` html +```html