Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: restore

Perhaps nothing in Tapestry has changed over the years so much as the way client-side JavaScript is supported. From the get go, the goal was to make JavaScript a first-class citizen in the Tapestry world, and make it easy to encapsulate JavaScript within components.

Div
stylefloat:right
titleRelated Articles
classaui-label
Content by Label
showLabelsfalse
showSpacefalse
titleRelated Articles
cqllabel in ("javascript","ajax") and space = currentSpace()

The legacy JavaScript page discusses the earlier approaches; the main feature of Tapestry 5.4 is a total rewrite of all things client-side, with the following goals:

  • Break the hard linkage of Tapestry to Prototype and Scriptaculous, by introducing an abstraction layer
  • Remove the clumsy Tapestry and T5 "namespaces"
  • Reduce the amount of page-specific JavaScript initialization
  • Make it easier to override behavior associated with client elements
  • Support CoffeeScript and (potentially) other languages that target JavaScript
  • Organize client-side JavaScript using modules
  • Make pages load faster
  • Integrate Bootstrap
  • Make it easier for rich client libraries such as Backbone or AngularJS to operate within a page
  • Properly document Tapestry's client support

...

That being said, jQuery is not the be-all and end-all either. Tapestry 5.4 introduces an abstraction layer, that allows many components to write code that doesn't care whether the foundation framework is Prototype or jQuery or something else. If you like jQuery then there's no problem: write your application using just jQuery and you can ignore a lot of the features in the abstraction layer. Your code will likely be just a bit more efficient.

If you are building a reusable component or library, writing to the abstraction layer may be worth the effort; it is entirely possible that someone may write a replacement for the abstraction layer that targets your favorite foundation framework, such as ExtJS, MooTools, or something not even known of today.

...

In Tapestry 5.4, the goal is to make things light. In most cases, there isn't a specific initialization function; instead a JavaScript module is loaded, and it installs one or more top-level event handlers; the elements has data- attributes that are used by those top level handlers to recognize which elements they are responsible for.

This is more of a full lifecycle approach; 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 searches 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 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 documentation about those events.

...

Most applications should transition to jQuery and feel free to use jQuery directly.  It is still best to inject module jquery into your own modules (usually as parameter $). 

...