Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
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

4,068 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
  • Be the first to comment

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

×