Chapter 14. Layout Widgets

Unfortunately, many web apps consume nontrivial amounts of time implementing and rediscovering CSS shenanigans to achieve layouts that have been realized many times already and that should be a lot easier than they often turn out to be. This chapter introduces the layout dijits, a number of useful containers for creating common layouts in markup. Layout containers allow you to automate incredibly common tasks such as producing a tabbed layout as well as producing arbitrary tiled layouts without resorting to custom CSS for floating content, calculating relative offsets, etc. Unlike the previous chapter on form widgets, this chapter is shorter, much simpler, and more predictable. There are only a handful of layout widgets; all of them have only a few configuration options and very few caveats.

Layout Dijit Commonalities

All layout dijits exist within the dijit.layout namespace and share a small set of baseline features that you should be aware of. In addition to inheriting from _Widget, _Container, and _Contained, they share a few extra commonalities. This section quickly reviews the commonalities, listed in Table 14-1, which are all pretty easy to get your head around.

Table 14-1. Layout dijit common methods

Name

Comment

isLayoutContainer

Returns whether the widget is a layout container.

layout( )

Overridden by widgets to size and position their contents (child widgets). This is called after startup, when the widget's content box is guaranteed to be set, and anytime the widget's size has been changed via resize.

resize(/*Object*/ size)

Used to explicitly set the size of a layout widget; accepts an object specifying the upper left along with a width and a height of the form {w : Integer, h: Integer, l : Integer, t : Integer}. (Anytime you override resize, you will almost always call layout in the overridden method because layout is the canonical location for handling size and positioning for the contained child widgets.)

An especially important takeaway from Table 14-1 is the relationship between layout and resize. To be clear, resize is used to change the size of widget, and it is almost always the case that resize calls layout to adjust the size of its children in response to resizing. Normally speaking, child nodes do not lay themselves out. The parent node lays them out inside of layout. As a general pattern, the startup lifecycle method kicks off resize, which in turn calls layout.

The layout dijits leverage features of _Container and _Contained especially heavily, so they are worth a review as well, provided in Table 14-2.

Table 14-2. Layout dijit container machinery

Name

Comment

removeChild(/*Object*/ dijit)

Removes the child widget from the container. (Silently fails if the widget is not a child or if the container does not have any children.)

addChild(/*Object*/ dijit, /*Integer?*/ insertIndex)

Adds a child widget to the container, optionally using the insertIndex to place it.

getParent( )

Commonly used by a child inside of a layout container to retrieve its parent. Returns a dijit instance.

getChildren( )

Commonly used by a layout container to enumerate each of its children dijits. Returns an Array of dijit instances.

getPreviousSibling( )

Used by descendants of StackContainer to reference the previous sibling, i.e., the one "to the left." Returns a dijit instance.

getNextSibling( )

Used by descendants of StackContainer to reference the next sibling, i.e., the one "to the right." Returns a dijit instance.

Programmatic Creation

As we'll see in upcoming examples, the pattern for programmatically creating layout dijits follows the same dijit creation pattern that involves providing a first argument with a collection of properties and a second parameter that provides a source node reference for the layout dijit. Once the layout dijit is created, the source node reference becomes the dijit's domNode. This all takes place via _Widget's create method, which was introduced as part of the dijit lifecycle in Chapter 12. Unlike many dijits you've learned about so far, however, you'll almost always need to explicitly call a layout dijit's startup method if you programmatically create layout dijits because they generally contain child widgets, and startup signals that the container is finished adding children—at which point the layout can proceed. After all, it wouldn't be prudent at all for a widget to lay itself out only to have other sibling widgets repeatedly drop in and restart the layout process. Thus, the parent's startup method generally involves calling the startup method on each child widget, which is the green light to start rendering.

Tip

If you are implementing a parent container, startup is your last chance to manipulate children before they are displayed.

Keyboard Support

Like with other all other dijits, keyboard support is quite full featured. You'll find that in almost all circumstances, the "obvious" keys work. For example, to navigate through an AccordionPane, you can use the up and down arrows as well as the Page Down and Page Up keys. In addition to providing accessibility as part of Dijit's a11y goals, this extensive keyboard support also enhances the general user experience.

Get Dojo: The Definitive Guide now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.