RAD CRUD
Rapid development of form-based applications.




                      1
Where did we stop?

• This presentation follows “CRUD with
  Dojo: the bread and butter of IT.”
 • http://lazutkin.com/blo...
A short narrative of…
• …the previous episode.
 • CRUD is a big hit in IT.
 • If only we had a way to improve good
    thi...
Suddenly!
• The sound of heavy breathing fills airwaves.
• Scared audience can hear how cold air
  rushes through myriad of...
Come to the Client Side,
         Luke!


           5
Sorry.
• That was my bronchitis acting up.
• So, Luke, we looked at what’s available in
  browsers:
  • A sorry mess of fo...
Dijit and DojoX
• Dijit and DojoX form widgets are good for
  CRUD:
 • Unified API to get/set values.
 • Unified events.
 • ...
Forms

• dijit.form.Form
 • Makes sure that all widgets are validated
    before submitting a form.
  • Gets/sets form wid...
dojox.form.manager
  The way to manage your forms.




                9
Simple data model

• The form manager is used to annotate
  complex form using simple Dojo markup.
• It views all controll...
Simple value model

• The form manager can get/set a value to
  any controlled element using the same API.
• It can get/se...
Simple event model
• The form manager can observe value
  changes of any controlled element using the
  same API.
• When v...
Observer

• An element can have any number of
  observers.
• An observer can be attached to any
  number of elements.
• Ob...
Architecture I
• The form manager is a collection of mixins
  located in dojox/form/manager/.
 • _Mixin.js provides all ba...
Architecture II

•   _NodeMixin.js adds 1st-class support to
    form elements (DOM nodes).
• _ValueMixin.js adds helpers ...
Architecture III

• _EnableMixin.js adds helpers to enable/
  disable form fields.
• _DisplayMixin.js adds helpers to show/...
Architecture IV

• Manager.js is an example widget, which
  includes all mixins and searches
  descendants to find controll...
Architecture V
• Instead of using Manager.js (or a subset of
  it), you can create a normal widget derived
  from proper m...
Practical examples
     Let’s rock and roll.




              19
Registering elements I
 <form action=”/doForm” id=”myForm”
  dojoType=”dojox.form.Manager”>
   <!-- form widgets are regis...
Registering elements II
 <form action=”/doForm” id=”myForm”
  dojoType=”dojox.form.Manager”>
   <!-- more follows -->
   <...
Registering elements III
• Explanations:
 • All 3 types of controlled elements are
    registered:
   • “name” – a form wi...
Registering elements IV
• More on DOM nodes:
   • By default DOM nodes cannot have
     values, but we can:
     • Show/hi...
Registering elements V
• “more” is a <div> node.
 • It will be used to show/hide its content.
 • Its value is unchanged an...
Registering elements VI
• We can register/unregister elements
  dynamically.
 • _Mixin.js: (un)registerWidget(),
    (un)r...
Populating values I

• Logically the form manager represent its
  form as a dictionary:
  var form = {
   name: ...,
   em...
Populating values II
• _ValueMixin.js provides all value helpers.
 • setFormValues(dict) sets values:
  var fm = dijit.byI...
Populating values III
• gatherFormValues(names) gets values:
 • A dictionary is returned as the result.
 • If “names” is o...
Populating values IV
• The last form of gatherFormValues()
  compliments setFormValues():
  // create our dictionary with ...
Populating values V

• If you want to read/write just one value use
  elementValue():
  // set value
  fm.elementValue(“na...
Observing elements I
<form action=”/doForm” id=”myForm”
 dojoType=”dojox.form.Manager”>
  <input type=”text” name=”name” v...
Observing elements II
• Explanations:
 • It is a slightly modified version of the
    registration example.
  • It has two ...
Observing elements III
• We can attach our observer declaratively
  as a regular method:
  <script type=”dojo/method” even...
Observing elements IV

• Slightly smarter observer:
  <script type=”dojo/method” event=”obReady”
   args=”value,name”>
   ...
Observing elements V

• Notes:
 • Observer is invoked when a value has
    changed.
   • Some text-based widgets do not fir...
Observing elements VI

• Notes:
   • Attached DOM nodes cannot have
     “change” events. And they cannot have
     observ...
_EnableMixin.js I

• This mixin is responsible for enabling/
  disabling form elements.
• gatherEnableState() is modeled a...
_EnableMixin.js II

• Three ways to collect the enabled status:
  // read states of all elements as true/false values
  en...
_EnableMixin.js III

• Enable/disable unconditionally:
  fm.enable();          // enable all
  fm.enable(true);      // th...
_EnableMixin.js IV

• Enable/disable using a dictionary:
  var en = fm.gatherEnableState(); // get all states
  …
  // ena...
_EnableMixin.js V

• disable() compliments enable() and returns
  the previous state:
  var en = fm.disable();        // d...
_DisplayMixin.js
• This mixin is responsible for showing/hiding
  controlled DOM nodes. It has the same
  semantics as _En...
_ClassMixin.js I
• This mixin is responsible for adding/
  removing CSS classes.
• Unlike other mixins, _ClassMixin.js is ...
_ClassMixin.js II

• Three ways to collect the class status:
  // read presence of a CSS class from all
  cs = fm.gatherCl...
_ClassMixin.js III

• Three ways to add class:
  // add a CSS class to all elements
  fm.addClass(cls);
  // add a class t...
_ClassMixin.js IV

• Three ways to remove class:
  // remove a CSS class from all elements
  fm.removeClass(cls);
  // rem...
Hints and tips
 And advanced techniques.




            47
Do you need it? I
• You have a multipart complex form.
 • It is unwise to show a huge form to end
    users. It is better ...
Do you need it? II
• A possible way to structure a form (the
  shopping basket style):
 • Split in logically independent b...
Do you need it? III
• Field values interact with each other.
 • You have complex validation rules
    involving several fo...
Do you need it? IV
• Working with form involves I/O, which
  depends on already entered values.
 • When chaining screens, ...
Do you need it? V
• Working with form involves I/O, which
  depends on already entered values.
 • When chaining screens, s...
Do you need it? VI

• Try to simplify as much as possible:
 • Use validating widgets whenever possible.
 • Carefully weigh...
Resetting values I

• Frequently end user realizes that the
  changes were not good and want go back.
• Simple and well-kn...
Resetting values II

• Restore the snapshot with setFormValues()
  when user wants to “reset”.
• This technique works well...
Suspending a form I
• Typical way to submit a form is:
 • Collect all necessary data fields.
   • In some cases you pre-pro...
Suspending a form II
• Analyze a return value from the server.
 • If errors were encountered:
   • Notify user about them....
Suspending a form III
• While you are busy doing I/O and waiting
  for a server, it makes sense to “suspend a
  form”, so ...
Suspending a form IV

• Obviously it helps that you inform an end
  user what is going on using a proper
  message.
• Less...
Suspending a form V
• Soft version of “suspending a form”
  happens when you want to update some
  elements dynamically by...
Suspending a form VI
• In the same category of “soft suspension” is
  a server-side validation.
  • Disable involved fields...
Field interactions I
• First you need to define what is an ultimate
  result of validation looks like.
• Example: city, sta...
Field interactions II
• The example can be solved by one
  observer attached to all three fields.
• Every time it is called...
Field interactions III

• One form of field interaction is to show
  unobtrusive error/warning messages
  depending on inpu...
Pseudo-fields
• Pseudo-fields:
 • They are not originated in a database.
 • Frequently they are not transmitted at all.
 • T...
That’s all folks!
  Questions? Suggestions?




            66
About me

• I am an independent software developer.
• My web site:
 • http://lazutkin.com
• Follow me on Tweeter:
 • http:...
Upcoming SlideShare
Loading in …5
×

RAD CRUD

3,971 views

Published on

More details on the form manager, and advanced techniques. It was delivered at dojo.connect on 2/10/2010. Blog post: http://lazutkin.com/blog/2010/feb/10/rad-crud/

Published in: Technology
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
3,971
On SlideShare
0
From Embeds
0
Number of Embeds
1,163
Actions
Shares
0
Downloads
73
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

RAD CRUD

  1. 1. RAD CRUD Rapid development of form-based applications. 1
  2. 2. Where did we stop? • This presentation follows “CRUD with Dojo: the bread and butter of IT.” • http://lazutkin.com/blog/2009/dec/2/crud-with-dojo/ • But for those who missed it, or wants to refresh their memory, I offer a small recap. 2
  3. 3. A short narrative of… • …the previous episode. • CRUD is a big hit in IT. • If only we had a way to improve good things and reduce bad things… • Profit! • If only we knew how… 3
  4. 4. Suddenly! • The sound of heavy breathing fills airwaves. • Scared audience can hear how cold air rushes through myriad of small tubes almost drowning the rhythmic clicking and clacking of multiple valves. • The deep voice seemingly from the guts of the eternal void itself says: 4
  5. 5. Come to the Client Side, Luke! 5
  6. 6. Sorry. • That was my bronchitis acting up. • So, Luke, we looked at what’s available in browsers: • A sorry mess of form elements with different get/set value API and events. • Good thing we have Dojo and Dijit! 6
  7. 7. Dijit and DojoX • Dijit and DojoX form widgets are good for CRUD: • Unified API to get/set values. • Unified events. • Better visual representations for certain values, e.g., sliders and spinners. • Support validation. 7
  8. 8. Forms • dijit.form.Form • Makes sure that all widgets are validated before submitting a form. • Gets/sets form widgets using a dictionary. • More can be found in dojox.form.manager 8
  9. 9. dojox.form.manager The way to manage your forms. 9
  10. 10. Simple data model • The form manager is used to annotate complex form using simple Dojo markup. • It views all controlled elements as a name- based dictionary of objects. • It can control: form widgets, form elements (DOM nodes), arbitrary DOM nodes. 10
  11. 11. Simple value model • The form manager can get/set a value to any controlled element using the same API. • It can get/set a group of values at the same time. 11
  12. 12. Simple event model • The form manager can observe value changes of any controlled element using the same API. • When value has changed an observer can be called. • An observer is a method, which is called with 4 parameters: new value, element name, element, and an event object. 12
  13. 13. Observer • An element can have any number of observers. • An observer can be attached to any number of elements. • Observers are used to implement all value- change-driven functionality. 13
  14. 14. Architecture I • The form manager is a collection of mixins located in dojox/form/manager/. • _Mixin.js provides all basic plumbing and can work with form widgets and simple DOM nodes. • _FormMixin.js implements functionality similar to dijit.form.Form. 14
  15. 15. Architecture II • _NodeMixin.js adds 1st-class support to form elements (DOM nodes). • _ValueMixin.js adds helpers to get/set values. • _ClassMixin.js adds addClass()/ removeClass() helpers. 15
  16. 16. Architecture III • _EnableMixin.js adds helpers to enable/ disable form fields. • _DisplayMixin.js adds helpers to show/hide DOM nodes. 16
  17. 17. Architecture IV • Manager.js is an example widget, which includes all mixins and searches descendants to find controlled elements. • When we talk about “the form manager” we usually mean a functionality provided by _Mixin.js, rather than actual Manager.js. 17
  18. 18. Architecture V • Instead of using Manager.js (or a subset of it), you can create a normal widget derived from proper mixins, and place all form elements in a normal template. • This is a great way to share the same form in several places. • Observers would be simple methods of your widget. 18
  19. 19. Practical examples Let’s rock and roll. 19
  20. 20. Registering elements I <form action=”/doForm” id=”myForm” dojoType=”dojox.form.Manager”> <!-- form widgets are registered automatically by _Mixin.js --> <input type=”text” name=”name” value=”” dojoType=”dijit.form.TextBox”><br> <!-- form nodes are registered automatically by _NodeMixin.js --> <input type=”text” name=”email” value=””><br> <!-- more to follow --> </form> 20
  21. 21. Registering elements II <form action=”/doForm” id=”myForm” dojoType=”dojox.form.Manager”> <!-- more follows --> <!-- attach points are registered automatically by _Mixin.js --> <div dojoAttachPoint=”more”> <span dojoAttachPoint=”notes” class=”dojoFormValue”></span> </div> </form> 21
  22. 22. Registering elements III • Explanations: • All 3 types of controlled elements are registered: • “name” – a form widget. • “email” – a form node (_NodeMixin.js is needed). • “more” and “notes” – DOM nodes. 22
  23. 23. Registering elements IV • More on DOM nodes: • By default DOM nodes cannot have values, but we can: • Show/hide them. • Add/remove CSS classes. • To indicate that a DOM node can have value we use “dojoFormValue” class. 23
  24. 24. Registering elements V • “more” is a <div> node. • It will be used to show/hide its content. • Its value is unchanged and unused. • “notes” is a <span> node. • It can have a value (“dojoFormValue”). • It is inside of “more”. 24
  25. 25. Registering elements VI • We can register/unregister elements dynamically. • _Mixin.js: (un)registerWidget(), (un)registerWidgetDescendants(). • _NodeMixin.js: (un)registerNode(), (un)registerNodeDescendants(). • (Un)registering attach points is trivial. 25
  26. 26. Populating values I • Logically the form manager represent its form as a dictionary: var form = { name: ..., email: ..., notes: ... }; // our form has 3 value fields 26
  27. 27. Populating values II • _ValueMixin.js provides all value helpers. • setFormValues(dict) sets values: var fm = dijit.byId(“myForm”); // set just one value: fm.setFormValues({name: “Bob”}); // set other values overriding “name” fm.setFormValues({name: “Mike”, email: “mike@i.am”, debug: “clearly fake email!”}); 27
  28. 28. Populating values III • gatherFormValues(names) gets values: • A dictionary is returned as the result. • If “names” is omitted, all values are read. • If “names” is an array, only names from the array are read. • If “names” is a dictionary, its keys are read, and values are ignored. 28
  29. 29. Populating values IV • The last form of gatherFormValues() compliments setFormValues(): // create our dictionary with a subset of values var dict = {name: “Bob”}; // set values (actually just one name) fm.setFormValues(dict); … // update values (the same subset) dict = fm.gatherFormValues(dict); 29
  30. 30. Populating values V • If you want to read/write just one value use elementValue(): // set value fm.elementValue(“name”, “Bob”); … // get value var name = fm.elementValue(“name”); 30
  31. 31. Observing elements I <form action=”/doForm” id=”myForm” dojoType=”dojox.form.Manager”> <input type=”text” name=”name” value=”” dojoType=”dijit.form.TextBox” observer=”obReady”><br> <input type=”text” name=”email” value=”” observer=”obReady”><br> <input type=”submit” name=”submit” disabled=”disabled”> <!-- more to follow --> </form> 31
  32. 32. Observing elements II • Explanations: • It is a slightly modified version of the registration example. • It has two fields and one disabled button. • Both fields are observed by the same observer “obReady”. 32
  33. 33. Observing elements III • We can attach our observer declaratively as a regular method: <script type=”dojo/method” event=”obReady” args=”value,name”> // our observer is stupid: // it enables the button, when value is not empty this.enable({submit: value != “”}); // we will go over enable() later </script> 33
  34. 34. Observing elements IV • Slightly smarter observer: <script type=”dojo/method” event=”obReady” args=”value,name”> // enable the button, when at least // one value is not empty var dict = this.gatherFormValues([“name”, “email”]); this.enable({submit: dict.name || dict.email}); </script> 34
  35. 35. Observing elements V • Notes: • Observer is invoked when a value has changed. • Some text-based widgets do not fire events on every key press. Force them: intermediateChanges=”true” 35
  36. 36. Observing elements VI • Notes: • Attached DOM nodes cannot have “change” events. And they cannot have observers. • Elements can have several observers listed separated by comma. 36
  37. 37. _EnableMixin.js I • This mixin is responsible for enabling/ disabling form elements. • gatherEnableState() is modeled after gatherFormValues() – the same interpolation of input values are performed. 37
  38. 38. _EnableMixin.js II • Three ways to collect the enabled status: // read states of all elements as true/false values en = fm.gatherEnableState(); // read states of two elements en = fm.gatherEnableState([“name”, “email”]); // read states of two elements en = fm.gatherEnableState({“name”: 1, “email”: 0}); // only keys are processed, all values are ignored 38
  39. 39. _EnableMixin.js III • Enable/disable unconditionally: fm.enable(); // enable all fm.enable(true); // the same as above fm.enable(false); // disable all var a = [“name”, “email”]; fm.enable(a); // enable two elements fm.enable(a, true); // the same as above fm.enable(a, false); // disable two elements 39
  40. 40. _EnableMixin.js IV • Enable/disable using a dictionary: var en = fm.gatherEnableState(); // get all states … // enable “name”, disable “email” fm.enable({name: true, email: false}); … fm.enable(en); // revert to old state 40
  41. 41. _EnableMixin.js V • disable() compliments enable() and returns the previous state: var en = fm.disable(); // disable all … fm.disable([“name”, “email”]); // disable two elements … // now let’s revert to the old state fm.enable(en); // == fm.disable(en) 41
  42. 42. _DisplayMixin.js • This mixin is responsible for showing/hiding controlled DOM nodes. It has the same semantics as _EnableMixin.js: • gatherDisplayState() behaves exactly like gatherEnableState(). • show() is like enable(). • hide is like disable(). 42
  43. 43. _ClassMixin.js I • This mixin is responsible for adding/ removing CSS classes. • Unlike other mixins, _ClassMixin.js is not wired for reversing states. • While it is possible to check for presence of a CSS class, there is no helpers to use it. It can be added in the future. 43
  44. 44. _ClassMixin.js II • Three ways to collect the class status: // read presence of a CSS class from all cs = fm.gatherClassState(cls); // read states of two elements cs = fm.gatherClassState(cls, [“name”, “email”]); // read states of two elements cs = fm.gatherClassState(cls, {“name”: 1, “email”: 0}); // only keys are processed, all values are ignored 44
  45. 45. _ClassMixin.js III • Three ways to add class: // add a CSS class to all elements fm.addClass(cls); // add a class to two elements fm.addClass(cls, [“name”, “email”]); // add a class to two elements fm.addClass(cls, {“name”: 1, “email”: 0}); // only keys are processed, all values are ignored 45
  46. 46. _ClassMixin.js IV • Three ways to remove class: // remove a CSS class from all elements fm.removeClass(cls); // remove a class from two elements fm.removeClass(cls, [“name”, “email”]); // remove a class from two elements fm.removeClass(cls, {“name”: 1, “email”: 0}); // only keys are processed, all values are ignored 46
  47. 47. Hints and tips And advanced techniques. 47
  48. 48. Do you need it? I • You have a multipart complex form. • It is unwise to show a huge form to end users. It is better to structure it so only a part is shown at any given time. • A part should have well defined logically entry and exit points with an intermediate validation. 48
  49. 49. Do you need it? II • A possible way to structure a form (the shopping basket style): • Split in logically independent blocks. • Organize blocks as a chain of screens validating each screen independently. • At the end of a chain – a summary screen, which allows to re-start edits. 49
  50. 50. Do you need it? III • Field values interact with each other. • You have complex validation rules involving several form fields. • Variant: you can auto-suggest a value of one field using values of other fields. • Variant: a value of one field restrict possible values of other fields. 50
  51. 51. Do you need it? IV • Working with form involves I/O, which depends on already entered values. • When chaining screens, screen boundaries can be used to do an intermediate I/O. • Variant: asynchronous server-side validation. 51
  52. 52. Do you need it? V • Working with form involves I/O, which depends on already entered values. • When chaining screens, screen boundaries can be used to do an intermediate I/O. • Variant: asynchronous server-side validation. 52
  53. 53. Do you need it? VI • Try to simplify as much as possible: • Use validating widgets whenever possible. • Carefully weigh in if you need to use _DisplayMixin.js or just proper layout widgets. 53
  54. 54. Resetting values I • Frequently end user realizes that the changes were not good and want go back. • Simple and well-known technique is to “reset a form” reverting to previous values. • Use gatherFormValues() to make a snapshot before editing. 54
  55. 55. Resetting values II • Restore the snapshot with setFormValues() when user wants to “reset”. • This technique works well for a part of form – just use a proper subset when taking a snapshot. 55
  56. 56. Suspending a form I • Typical way to submit a form is: • Collect all necessary data fields. • In some cases you pre-process them. • In some cases you produce new synthetic fields. • Submit it using XHR to a server. 56
  57. 57. Suspending a form II • Analyze a return value from the server. • If errors were encountered: • Notify user about them. • Allow to re-edit a form so it can be resubmitted again. • Redirect, or reset, if success. 57
  58. 58. Suspending a form III • While you are busy doing I/O and waiting for a server, it makes sense to “suspend a form”, so no editing can be done. • Use disable() to disable all visible fields while waiting. • Save a snapshot returned by disabled() – it can be used later to recreate the previous state. 58
  59. 59. Suspending a form IV • Obviously it helps that you inform an end user what is going on using a proper message. • Less elegant way to do the same is to use a modal message visible until you get results from a server. 59
  60. 60. Suspending a form V • Soft version of “suspending a form” happens when you want to update some elements dynamically by loading values from a server. • In this case you should disable only affected elements, show a proper message next to them while waiting. • After the update was done, enable them. 60
  61. 61. Suspending a form VI • In the same category of “soft suspension” is a server-side validation. • Disable involved fields. • Tell user what is going on. • Wait for a response. • Update messages and enable fields back. 61
  62. 62. Field interactions I • First you need to define what is an ultimate result of validation looks like. • Example: city, state, and zip should match, otherwise we cannot advance to the next screen. • In this example we have 3 input fields and one output: enabled/disabled “Next” button. 62
  63. 63. Field interactions II • The example can be solved by one observer attached to all three fields. • Every time it is called, it reads 3 values, does its magic, sets a proper enabled/ disabled flag on the button, and updates error messages. • The same way we can solve most validation problems. 63
  64. 64. Field interactions III • One form of field interaction is to show unobtrusive error/warning messages depending on input values. • Usually such messages go to DOM nodes, and effectively are pseudo-fields. 64
  65. 65. Pseudo-fields • Pseudo-fields: • They are not originated in a database. • Frequently they are not transmitted at all. • They are purely for UI convenience. • Pseudo-fields are a powerful tool, but cannot be generalized. 65
  66. 66. That’s all folks! Questions? Suggestions? 66
  67. 67. About me • I am an independent software developer. • My web site: • http://lazutkin.com • Follow me on Tweeter: • http://twitter.com/uhop 67

×