Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

This is more of a full lifecycle approach; there's no danger of  adding or removing page content (such as with a Zone component) is both cheaper and less error prone using top-level event handlers than per-element event handlers; there's also less of a chance of memory leaks under Internet Explorer.

Note

Internet Explorer is pretty well known for memory leaks; its DOM and JavaScript run in different kinds of memory, which are garbage collected individually. This means that a reference from JavaScript to a DOM element will keep the DOM element live, even if that's the only reference to the DOM element anywhere. Meanwhile, event handler JavaScript functions are kept live from the DOM element, making a cycle that can't be broken. Libraries like Prototype and jQuery have to expend some effort to break this link by unregistering event handlers from DOM elements when removing them from the DOM.

A specific example of this approach is how client-side validation now works; in the past, there was a complex system of classes and event listeners that were specific to each individual field. Field controllers had to register with Form controllers. Validators had to register with Field controllers.

Under 5.4, there are a number of data- attributes that can be attached to any DOM element. A form will search for elements with a non-blank value for data-validation; each such element has a series of custom events triggered on it. The top-level handlers for those events will receive notifications for elements throughout the document.

Code Block
titlet5/core/validation.coffee (partial)
define ["underscore", "./dom", "./events", "./utils", "./messages", "./fields"],
  (_, dom, events, utils, messages) ->


  ...
 
    dom.onDocument events.field.optional, "[data-optionality=required]", (event, memo) ->
      if utils.isBlank memo.value
        memo.error =  (@attr "data-required-message") or "REQUIRED"


  ...
 
    dom.onDocument events.field.validate, "[data-validate-min-length]", (event, memo) ->
      min = parseInt @attr "data-validate-min-length"
      if memo.translated.length < min
        memo.error = (@attr "data-min-length-message") or "TOO SHORT"
        return false

The t5/core/events module defines constants for different custom event name, it's also a handy place to hang hang documentation about those events.

The t5/core/dom namespace is the abstraction layer.  onDocument is a handy way to attach a top-level event handler.

Fields that are required will have the attribute data-optionality=required; the event handler is passed a memo object that includes a value property, the value from the field. This makes it easier to generate an error if the value is blank.  Because the exact error message may be customized or localized, it is provided in the element as well, as the data-required-message attribute. Setting memo.error to a validation error string will cause the field to be decorated with the error message and will indicate that the form itself is in error and not ready for submission.

A different event is triggered after the optionality check; The memo.translated property is the value translated before validation (for a numeric field, it would be translated from a string to a number, for example). Again, the error property is set, and the return false ensures that the event will stop bubbling to containing elements or event handlers.