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, “Layout dijit common methods”, which are all
pretty easy to get your head around.
Table 14.1. Layout dijit common methods
|
Name |
Comment |
|---|---|
|
|
Returns whether the widget is a layout container. |
|
|
Overridden by widgets
to size and position their contents (child widgets). This is
called after |
|
|
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
|
An especially important takeaway from Table 14.1, “Layout dijit common methods” 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, “Layout dijit container machinery”.
Table 14.2. Layout dijit container machinery
|
Name |
Comment |
|---|---|
|
|
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.) |
|
|
Adds a child widget to
the container, optionally using the |
|
|
Commonly used by a child inside of a layout container to retrieve its parent. Returns a dijit instance. |
|
|
Commonly used by a
layout container to enumerate each of its children dijits.
Returns an |
|
|
Used by descendants of
|
|
|
Used by descendants of
|
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, Dijit Anatomy and Lifecycle. 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.
ContentPane
A ContentPane is the most
basic layout tile and it inherits directly from _Widget; conceptually, it is like a
super-duper variation of an iframe
except that it fits right into the page with all sorts of bells and
whistles, not the least of which are the ability to render arbitrary
snippets of HTML (not just full documents), reload content via XHR on
demand, render widgets, and respect the page's theme. More often than
not, a ContentPane is contained
within another widget such as a TabContainer, although a ContentPane has several interesting uses
cases on its own.
In its most generic usage, a layout pane does nothing special at all, as shown in Example 14.1, “Creating a ContentPane in markup”.
Example 14.1. Creating a ContentPane in markup
<html>
<head><title>Fun with ContentPane!</title>
<link rel="stylesheet" type="text/css"
href="http://o.aolcdn.com/dojo/1.1/dojo/resources/dojo.css" />
<link rel="stylesheet" type="text/css"
href="http://o.aolcdn.com/dojo/1.1/dijit/themes/tundra/tundra.css" />
<script
djConfig="parseOnLoad:true",
type="text/javascript"
src="http://o.aolcdn.com/dojo/1.1/dojo/dojo.xd.js">
</script>
<script type="text/javascript">
dojo.require("dijit.layout.ContentPane");
</script>
</head>
<body class="tundra">
<div dojoType="dijit.layout.ContentPane">
Nothing special going on here.
</div>
</body>
</html>Tip
When browsing the source code or reading about Dojo online,
you may notice that there is also a LinkPane dijit. Over the course of time,
ContentPane evolved to absorb
much of what LinkPane used to do,
and it is likely that LinkPane
will become deprecated because it offers a trivial amount of
built-in functionality beyond that of ContentPane.
However, you can trivially fetch arbitrary content from a server
and render it into the page by merely providing a reference to the
server side URL. Suppose that a server-side URL called
foo returns a snippet of text; you could use the
ContentPane to display it like
so:
<div id="foo" preload="false" dojoType="dijit.layout.ContentPane" href="foo">
In this particular case, the foo URL might
have returned just a simple string value, although it could have
returned a widget that would have been automatically parsed and
rendered into the page. Just note that the widget must already have
been dojo.require'd into the page.
For example, let's suppose the foo URL returned <div
dojoType="dijit.form.Textarea"></div>, then by
default, the dijit would be parsed and rendered into the page.
Table 14.3, “ContentPane API” presents a summary of
everything that a ContentPane
supports.
Table 14.3. ContentPane API
|
Name |
Type |
Comment |
|---|---|---|
|
|
String |
Used to designate the external data the pane should load. |
|
|
Boolean |
If |
|
|
Boolean |
If |
|
|
Boolean |
Acts just like the
|
|
|
Boolean |
Used to force the pane
to load content, even if it is not initially visible. (If the
node is styled with |
|
|
Boolean |
Used to indicate
whether the pane should reload every time the pane goes from a
hidden state to a visible state. |
|
|
String |
Defined in |
|
|
String |
Defined in |
|
|
Boolean |
Used to provide an explicit status for whether content is loaded. Useful for inquiries involving content that is often refreshed. |
|
|
Function |
Used to force the content to refresh by downloading it again. |
|
|
Function |
Used to change the
location of the external content for the dijit. If |
|
|
Function |
Used to explicitly set local content for the pane. |
|
|
Function |
Cancels the in-progress download of content. |
|
|
Function |
Extension point that is called after the load (and optional parsing of widgets) takes place. |
|
|
Function |
Extension point that is
called before existing content is cleared by a refresh,
|
|
|
Function |
Extension point that is called just before the download begins. By default, returns the string that is displayed as the loading message. |
|
|
Function |
Extension point that is called when DOM errors occur. The string that is returned is what is displayed to the user. |
|
|
Function |
Extension point that is called if an error occurs during the download. By default, returns the string that is displayed as the error message. |
|
|
Function |
Extension point that is called when the download completes. |
Given an existing node called foo, you could programmatically create a
ContentPane like so:
var contentPane = new dijit.layout.ContentPane({ /* properties*/, "foo");
contentPane.startup( ); //good practice to get in the habit of always calling startupBecause ContentPane is not a
descendant of _Container, there are
no built-in methods for adding children to a ContentPane. However, you can use a ContentPane's domNode reference to append another node
inside of it using plain old JavaScript, which works just fine. For
example, using the existing content pane from the previous
example:
contentPane.domNode.appendChild(someOtherDijit.domNode);
Tip
You may be wondering why ContentPane does not directly support the
interface provided by _Container.
The unofficial answer is that a ContentPane, in general, does not need to
perform a specific action when a child is placed into it for a
specific reason. The reasons for adding children to a ContentPane are wide and varied. If you
really wanted to, however, you could mixin or extend
_Container into ContentPane.
BorderContainer
Warning
BorderContainer is a new
layout dijit introduced in version 1.1 that resulted in LayoutContainer and SplitContainer getting deprecated because
BorderContainer is essentially a
union of the two. Although you may see examples on the web using
LayoutContainer and SplitContainer, it is not a good idea to
start building an application with deprecated features. For this
reason, these two deprecated widgets are not covered in this
book.
A BorderContainer provides an
easy way to define a layout that normally involves several layout
tiles that occur on the top/bottom/left/right/center,
top/bottom/center, or left/right/center of the page. These tiles may
have resizable handles, so the BorderContainer is an especially notable
value-added widget in that it simplifies what could have otherwise
been a grueling workload into a really simple widgetized solution. As
you might have guessed, it is called a "border" container because up
to four tiles surround its border with the center filling in to
whatever is leftover.
Table 14.4, “BorderContainer API” shows the API.
Table 14.4. BorderContainer API
|
Name |
Type |
Comment |
|---|---|---|
|
|
String |
Valid values include
|
|
|
Boolean |
Whether to continuously
resize while the mouse drags or to resize on the |
|
|
Boolean |
Whether to save splitter positions as a cookie. |
When using a BorderContainer,
the additional attributes shown in Table 14.5, “Attributes available to children of BorderContainer”, which BorderContainer depends on, are available
via ContentPane.
Tip
You might find it interesting to know that the means of making
these additional attributes available via ContentPane is that the BorderContainer resource file extends
_Widget's prototype to contain
these values behind the scenes. This is a clever solution to the
problem as it uses JavaScript's dynamism to provide these extras on
demand, instead of requiring an a priori
solution, which would really junk up and create unnecessary
couplings on ContentPane's
implementation.
Table 14.5. Attributes available to children of BorderContainer
A layout that involves a top and bottom that extends the width of the container is called a headline layout, and a layout that involves a left and right that extends the width of the container is called a sidebar layout. Either layout can optionally contain additional tiles that increase the number of layout areas from three to five. In any case, the remaining space that is leftover is the center area that gets filled in with the center tile.
Let's kick things off with a simple headline layout in markup, shown in Example 14.2, “Creating a BorderContainer in markup”. The top will be a blue pane, the bottom a red panel, and the middle will remain white. The top pane has minimum height of 10 pixels and a maximum height of 100 pixels (its default height).
Example 14.2. Creating a BorderContainer in markup
<html>
<head><title>Fun with BorderContainer!</title>
<link rel="stylesheet" type="text/css"
href="http://o.aolcdn.com/dojo/1.1/dojo/resources/dojo.css" />
<link rel="stylesheet" type="text/css"
href="http://o.aolcdn.com/dojo/1.1/dijit/themes/tundra/tundra.css" />
<script
djConfig="parseOnLoad:true",
type="text/javascript"
src="http://o.aolcdn.com/dojo/1.1/dojo/dojo.xd.js">
</script>
<script type="text/javascript">
dojo.require("dijit.layout.ContentPane");
dojo.require("dijit.layout.BorderContainer");
dojo.require("dojo.parser");
</script>
</head>
<body class="tundra">
<div dojoType="dijit.layout.BorderContainer" design="headline"
style="height:500px;width:500px;border:solid 3px;">
<div dojoType="dijit.layout.ContentPane" region="top"
style="background-color:blue;height:100px;" splitter="true"
minSize=10 maxSize=100>top</div>
<div dojoType="dijit.layout.ContentPane" region="center">center</div>
<div dojoType="dijit.layout.ContentPane" region="bottom"
style="background-color:red;height:100px;" splitter="true">bottom</div>
</div>
</body>
</html>Adding tiles to fill in the left and right sides takes only two
additional ContentPane dijits, as
shown in Figure 14.1, “Left: the BorderContainer before adding in additional panels
on the left and right; right: the BorderContainer after adding in
left and right panels”.
Consider the following revision to the BODY tag:
<body class="tundra">
<div dojoType="dijit.layout.BorderContainer"
design="headline" style="height:500px;width:500px;border:solid 3px;">
<div dojoType="dijit.layout.ContentPane" region="top"
style="background-color:blue;height:100px;" splitter="true"
minSize=10 maxSize=100>top</div>
<div dojoType="dijit.layout.ContentPane" region="center">center</div>
<div dojoType="dijit.layout.ContentPane" region="bottom"
style="background-color:red;height:100px;" splitter="true">bottom</div>
<div dojoType="dijit.layout.ContentPane" region="left"
style="background-color:yellow;width:100px;" splitter="true">
left</div>
<div dojoType="dijit.layout.ContentPane" region="right"
style="background-color:green;width:100px;" splitter="true"
>right</div>
</div>
</body>Figure 14.1. Left: the BorderContainer before adding in additional panels on the left and right; right: the BorderContainer after adding in left and right panels
Like all other dijits, programmatically creating a BorderContainer entails the same basic
constructor function that takes a collection of properties and a
source node. Adding in the child ContentPanes involves systematically
creating them one by one as well. Although more tedious than markup,
it's the same basic pattern. Example 14.3, “Programmatically creating a BorderContainer” shows how you'd create Example 14.2, “Creating a BorderContainer in markup”
programmatically.
Example 14.3. Programmatically creating a BorderContainer
<html>
<head><title>Fun with BorderContainer!</title>
<link rel="stylesheet" type="text/css"
href="http://o.aolcdn.com/dojo/1.1/dojo/resources/dojo.css" />
<link rel="stylesheet" type="text/css"
href="http://o.aolcdn.com/dojo/1.1/dijit/themes/tundra/tundra.css" />
<script
djConfig="parseOnLoad:true",
type="text/javascript"
src="http://o.aolcdn.com/dojo/1.1/dojo/dojo.xd.js">
</script>
<script type="text/javascript">
dojo.require("dijit.layout.BorderContainer");
dojo.require("dijit.layout.ContentPane");
dojo.require("dojo.parser");
dojo.addOnLoad(function( ) {
//the BorderContainer
var bc = new dijit.layout.BorderContainer(
{
design: "headline",
style: "height:500px;width:500px;border:solid 3px"
},
"bc"
);
var topContentPane = new dijit.layout.ContentPane(
{
region: "top",
style: "background-color:blue;height:100px;",
splitter: true,
minSize : 10,
maxSize : 100
},
document.createElement("div")
);
var centerContentPane = new dijit.layout.ContentPane(
{
region: "center"
},
document.createElement("div")
);
var bottomContentPane = new dijit.layout.ContentPane(
{
region: "bottom",
style: "background-color:red;height:100px;",
splitter: true
},
document.createElement("div")
);
bc.startup( ); // do initial layout (even though there are no
children)
//now add the children.
bc.addChild(topContentPane);
bc.addChild(centerContentPane);
bc.addChild(bottomContentPane);
});
</script>
<head>
<body class="tundra">
<div id="bc"></div>
</body>
</html>Tip
The previous example called startup(
) to do initial layout and then used the addChild method to add children. The
following approach would also have worked:
bc.domNode.appendChild(topContentPane.domNode); bc.domNode.appendChild(centerContentPane.domNode); bc.domNode.appendChild(bottomContentPane.domNode); bc.startup( );
BorderContainer dijits are
quite flexible and can be nested arbitrarily if the situation calls
for it. They're also a great way to set up a headline style or sidebar
style layout with virtually no effort, although you should generally
consider plain old CSS for production situations in which widgets
don't add any value.
StackContainer
A StackContainer is a layout
dijit that displays a sequence of tiles one at a time. A StackContainer is conceptually just like a
slideshow in which you can page backward and forward through a "stack"
of tiles. Like LayoutContainer, you
provide any number of child widgets to the StackContainer, and it takes care of the
display. In its most basic usage, you simply page through the
available tiles, as shown in Example 14.4, “Creating a StackContainer in markup”.
Example 14.4. Creating a StackContainer in markup
<div id="stack" dojoType="dijit.layout.StackContainer"
style="width:100px; height:100px; margin:5px; border:solid 1px;">
<div dojoType="dijit.layout.ContentPane">
One fish...
</div>
<div dojoType="dijit.layout.ContentPane">
Two fish...
</div>
<div dojoType="dijit.layout.ContentPane">
Red fish...
</div>
<div dojoType="dijit.layout.ContentPane">
Blue fish...
</div>
</div>
<button dojoType="dijit.form.Button"><
<script type="dojo/method" event="onClick" args="evt">
dijit.byId("stack").back( );
</script>
</button>
<button dojoType="dijit.form.Button">>
<script type="dojo/method" event="onClick" args="evt">
dijit.byId("stack").forward( );
</script>
</button>The usual container and generic layout methods apply to StackContainer; additionally, you should
also note the features in Table 14.6, “StackContainer API”.
Table 14.6. StackContainer API
|
Name (default) |
Type |
Comment |
|---|---|---|
|
|
Boolean |
Used to change the size
of the currently displayed child to match the container's
size. |
|
|
Object |
References the
currently selected child widget. |
|
|
Function |
Used to select a specific child widget. |
|
|
Function |
Used to page forward to the next child widget. |
|
|
Function |
Used to page backward to the previous child widget. |
Tip
The StackContainer also
supports several additional features:
A
closeChild(/*Object*/ child)methodAn
onClose( )extension pointChildren may exhibit the
closeable,title, andselectedattributesTopics that are published when children are added, removed, or selected,
<id>-addChild,<id>-removeChild, and<id>-selectChild, respectively
Because these features are most commonly associated with the
TabContainer (which inherits from
StackContainer), however, their
formal introduction will be delayed until the next section.
If you've followed along with the previous example of programmatically creating layout dijits, Example 14.5, “Programmatically creating a StackContainer” should seem awfully familiar.
Example 14.5. Programmatically creating a StackContainer
var container = new dijit.layout.StackContainer({}, "foo");
var leftChild = new dijit.layout.ContentPane({});
leftChild.domNode.innerHTML="page 1";
var rightChild = new dijit.layout.ContentPane({});
rightChild.domNode.innerHTML="page 2";
container.addChild(leftChild);
container.addChild(rightChild);
container.startup( );
/* Skip from page 1 to page 2 with... */
dijit.byId("foo").forward( );Procrastination (a.k.a. Lazy Loading) May Yield Better Performance
The previous example uses explicit buttons for paging, but it
is not uncommon to use a StackContainer as an application container
to control the flow of an application with multiple pages. For
example, your application might initially display a page with a
search bar; once a button is pressed to trigger a search, you might
page forward to display a search results screen. Assuming that
you've defined every page of the application as a child of a
StackContainer, this approach has
the advantage of never explicitly reloading a page—a little bit of
snazzy flare for a Web 2.0 style interface.
Although loading the entire application at one time when the
page loads may be the best option for some
circumstances, you could also elect to lazy-load content by
configuring a child ContentPane
to lazy load via its href
attribute. Recall that this behavior is controlled by a ContentPane's preload attribute, which when false (the default) does not fetch content
until it becomes visible. You can watch the Firebug console to
confirm this behavior. For example, if the URL referenced below,
which is entitled blueFish
contained the text "Blue fish . . . " from Example 14.4, “Creating a StackContainer in markup”, then the following
adjustment would lazy load the fourth page of the StackContainer:
<div dojoType="dijit.layout.ContentPane" href="blueFish"></div>
Lazy loading is ideal for situations in which there may be application features that are essential, but not often used. A preferences pane is a prime candidate for lazy loading that often involves gobs of controls that may not appear on any other page of the application.
TabContainer
As it turns out, a TabContainer is really just a fancier
version of a StackContainer—the
primary difference is that a TabContainer comes with a snazzy set of tabs
that can be used to control which page is displayed at any given time.
In fact, the TabContainer inherits
from StackContainer and provides
only a few additional features that pertain to the list of tabs
itself. Example 14.6, “Creating a TabContainer in markup”
illustrates basic usage of the TabContainer.
Example 14.6. Creating a TabContainer in markup
<div dojoType="dijit.layout.TabContainer"
style="width:225px; height:100px; margin:5px; border:solid 1px;">
<div dojoType="dijit.layout.ContentPane" title="one">
One fish...
</div>
<div dojoType="dijit.layout.ContentPane" title="two">
Two fish...
</div>
<div dojoType="dijit.layout.ContentPane" title="red"
closable=
"true">Red fish...
<script type="dojo/method" event="onClose" args="evt">
console.log("Closing", this.title);
return true; //must return true for close to occur!
</script>
</div>
<div dojoType="dijit.layout.ContentPane" title="blue">
Blue fish...
</div>
</div>Take special note that the tab controls take care of themselves;
you simply provide a title
attribute to each child of the TabContainer, and the rest is handled with
internal automation that you don't have get be directly involved with
(and that's the best kind). Additionally, notice that you may provide
a closeable tab via the closable
attribute, and an optional onClose
extension point may perform a custom action when a close does occur.
Be careful, though, because if true
is not returned from onClose, the
tab will not close.
Table 14.7, “TabContainer API” lists the features that
pertain to TabContainer.
Table 14.7. TabContainer API
|
Name |
Type |
Comment |
|---|---|---|
|
|
String |
Mixed into |
|
|
Boolean |
Mixed into |
|
|
Function |
An extension point
mixed into |
|
|
String |
Specifies where the
list of tab buttons should appear. Possible values include
|
|
|
This functionality is
inherited from |
Tip
The buttons you see on a tab container are honest to goodness
dijit.form.Button buttons; do
with them as you will.
Just like with StackContainer, you may lazy load content in
a TabContainer via a ContentPane, as long as preload is set to be false.
And now, Example 14.7, “Programmatically creating a TabContainer” shows how to use programmatic creation.
Example 14.7. Programmatically creating a TabContainer
var container = new dijit.layout.TabContainer({
tabPosition: "left-h",
style : "width:200px;height:200px;"
}, "foo");
var leftChild = new dijit.layout.ContentPane({title : "tab1"});
leftChild.domNode.innerHTML="tab 1";
var rightChild = new dijit.layout.ContentPane({title : "tab2", closable: true});
rightChild.domNode.innerHTML="tab 2";
container.addChild(leftChild);
container.addChild(rightChild);
container.startup( );AccordionContainer
Like a TabContainer, AccordionContainer inherits from StackContainer and is a means of displaying
one child at a time from a collection of widgets. The visual
difference is that the container looks like a vertical accordion, and
animates when each child is selected.
One important difference in how you use AccordionContainer, however, is that you
must use a special child container called AccordionPane that provides an explicit
wrapper for its child widgets. The actual reasoning for why this is
the case is not very interesting and has to do with how the underlying
implementation for AccordionContainer. In general, just treat
an AccordionPane like a ContentPane and be on your merry way.
Warning
As of version 1.1, AccordionPane does not support nested
layout widgets such as SplitContainer; virtually all other types
of content, however, should work just fine.
Example 14.8, “Creating an AccordionContainer in markup” shows a
simple AccordionContainer in
action.
Example 14.8. Creating an AccordionContainer in markup
<div id="foo" dojoType="dijit.layout.AccordionContainer"
style="width:150px; height:150px; margin:5px">
<div dojoType="dijit.layout.AccordionPane" title="one">
<p>One fish...</p>
</div>
<div dojoType="dijit.layout.AccordionPane" title="two">
<p>Two fish...</p>
</div>
<div dojoType="dijit.layout.AccordionPane" title="red">
<p>Red fish...</p>
</div>
<div id="blue" dojoType="dijit.layout.AccordionPane" title="blue">
<div dojoType="dijit.layout.ContentPane" href="blueFish"></div>
</div>
</div>With respect to API, AccordionContainer itself provides only one
additional attribute beyond what StackContainer offers, shown in Table 14.8, “AccordionContainer API”.
Table 14.8. AccordionContainer API
|
Name (default) |
Type |
Comment |
|---|---|---|
|
|
Integer |
An attribute of
|
Although we could leave programmatic creation as an exercise for
the interested reader, there is a slight difference to the creation
pattern because AccordionPane is a
dijit on its own, as shown in Example 14.9, “Programmatically creating an AccordionContainer”.
Example 14.9. Programmatically creating an AccordionContainer
var container = new dijit.layout.AccordionContainer({}, "foo");
var content1 = dojo.doc.createElement("p");
content1.innerHTML = "content 1";
var ap1 = new dijit.layout.AccordionPane({title: "pane1", selected : true}, content1);
container.addChild(ap1);
var content2 = dojo.doc.createElement("p");
content2.innerHTML = "content 2";
var ap2 = new dijit.layout.AccordionPane({title: "pane2"}, content2);
container.addChild(ap2);
container.startup( );Rendering and Visibility Considerations
You may have noticed while working through the examples in this chapter that you usually see the layout occur as the page loads; for example, you might see ordinary text HTML representing some of the layout content, and then all of a sudden it magically transforms into this great-looking layout. While not totally unacceptable, you will probably not want to see the rendering take place in many situations.
A common technique for working around the situation is to
initially set the body of the page to be hidden, and then when the
page finishes loading, make it visible all at one time. Accomplishing
this technique is quite simple, and you merely have to provide a style
(or class) indicating that the body of the page should be hidden, like
so: <body
style="visibility:hidden;"> should do the trick. Just
remember to add the corresponding call to make it visible at the
desired time. Assuming you've made the entire body hidden, adding a
dojo.style(dojo.body( ), "visibility",
"visible") to a dojo.addOnLoad displays the page's content.
Any callback could be used in place of page load if for some reason
you wanted to delay showing the page until some arbitrary event
occurred (like an asynchronous callback that provides data for a
custom widget, perhaps).
Tip
Recall that the difference between the CSS styles of
visibility and display has to do with taking up space on the screen.
In general, nodes styled with visibility:hidden are hidden from display
but still take up space; nodes styled with display:none would not be visible and
would take up no space—resulting in a noticeable shift of content
when the display is changed to
display:block.
One caveat that should be noted, however, is that layout
containers do not always respond well when they are initially created
within a hidden container. If you find that your layout containers are
not visible when they should be, you may need to manually call their
resize( ) method to force them to
render properly. Historically, this issue has especially been the case
when displaying a layout container within a dijit.Dialog.
Warning
Layout dijits do not always render properly if they are
created in context that does not immediately make them visible.
Almost all of the time, you can simply call the layout container's
resize( ) method to render
it.
Summary
After reading this chapter, you should be able to:
Appreciate the common design challenges (tabbed layouts, for example) that layout dijits alleviate
Understand the basic features provided by the various layout dijits
Create arbitrary layouts with the layout dijits both in markup and programmatically
Use
BorderContainerto create flexible, tiled layouts that can arbitrarily resizeUse
ContentPaneto lazy load content either as a standalone or as part of another dijitUse
StackContainerandTabContainerto display multiple pages of data in an applicationUnderstand some of the considerations with respect to initially displaying layout dijts as being hidden
Understand the existing limitations of
AccordionPanewith respect to embedding layout dijitsUnderstand the role that the base classes
_Containerand_Containedplay with the layout dijits
Application widgets are coming up next.






Add a comment



Add a comment