Skip to Content | Skip to Navigation


dijit.popup

Project owner:Bill Keese
since:V?

Introduction

dijit/popup is the main mechanism within dijit that enables the creation of pop-ups like dropdowns and tooltips. It is used by every widget that creates a pop-up around another element.

Parent widgets

When creating a pop-up, there are usually two widgets involved:

  • The parent widget, which controls opening and closing of the pop-up
  • The pop-up widget itself

Opening a pop-up from a parent widget involves calling popup.open with a kwArgs object that provides information about the pop-up and its related parent widget. The available properties for this object are:

parent (Widget)
The widget that is displaying the pop-up.
popup (Widget, required)
The widget to display as a pop-up. This can be any dijit widget; some widgets that are commonly used as popups include dijit.ColorPalette, dijit.Menu, and dijit.Calendar.
around (DomNode)
A DOM node that should be used as a reference point for placing the pop-up. For pop-ups that are not meant to be placed around an element, use x and y instead
x (number)
The absolute horizontal position in pixels at which to place the pop-up.
y (number)
The absolute vertical position in pixels at which to place the pop-up.
orient (string[])

When placing a pop-up around a DOM node, it is possible to specify where the pop-up should appear around it by providing an array of position strings. Dijit will try each position in order until the pop-up appears fully within the viewport. Possible values are:

  • before: places drop down to the left of the anchor node/widget, or to the right in the case of RTL scripts like Hebrew and Arabic
  • after: places drop down to the right of the anchor node/widget, or to the left in the case of RTL scripts like Hebrew and Arabic
  • above: drop down goes above anchor node
  • above-alt: same as above except right sides aligned instead of left
  • below: drop down goes below anchor node
  • below-alt: same as below except right sides aligned instead of left

If left undefined, the default value is [ "below", "below-alt", "above", "above-alt" ].

onCancel (function())
A callback that is executed when the user has tried to cancel the pop-up by either hitting ESC or by using the pop-up’s cancel mechanism.
onClose (function())
A callback that is executed when the pop-up is actually closed by popup.close.
onExecute (function())
A callback that is executed when a user has “executed” a function in the pop-up, like selecting a menu option.
padding ({x: Number, y: Number})
An object that specifies extra padding that should be given to the area around the pop-up when determining its placement.

While only the popup property is required, most pop-ups will normally need to also provide onCancel and onExecute callbacks (as explained below) as well as either an around or x and y properties.

Here’s an example that roughly illustrates how dijit/_HasDropDown opens and closes pop-ups:

var self = this;

// wrap the pop-up widget and position it offscreen so
// that it can be measured by the widget’s startup method
popup.moveOffScreen(dropDown);

// if the pop-up has not been started yet, start it now
if(dropDown.startup && !dropDown._started){
    dropDown.startup();
}

// make the pop-up appear around aroundNode
popup.open({
    parent: this,
    popup: dropDown,
    around: aroundNode,
    orient: this.dropDownPosition,
    onExecute: function(){
        popup.close(dropDown);
    },
    onCancel: function(){
        popup.close(dropDown);
    },
    onClose: function(){
        domAttr.set(self._popupStateNode, "popupActive", false);
        domClass.remove(self._popupStateNode, "dijitHasDropDownOpen");
    }
});

domAttr.set(this._popupStateNode, "popupActive", "true");
domClass.add(this._popupStateNode, "dijitHasDropDownOpen");

As you can see, there are three essential calls here, popup.moveOffScreen, popup.open, and popup.close. popup.moveOffScreen wraps the widget in a container, appends it to the <body>, then moves it off-screen so that any measurement dropDown.startup needs to do is possible. Once that’s done, it opens the pop-up by calling popup.open. Finally, the onExecute and onCancel callbacks both call popup.close, passing in the correct pop-up widget to close.

It’s important to note here that the parent widget is responsible for both opening and closing the pop-up. This architecture was used so that the parent widget is always aware of whether or not its child pop-up is open, and so that it can easily perform any necessary clean-up or other relevant activity once its pop-up has closed.

Pop-up widgets

Any normal widget can be used as a pop-up. For example, dijit.Calendar is a normal widget that can be displayed inline in the page, but is used as a pop-up by the DateTextBox widget. In other words, there’s no need for a :ref:PopupWidget base class for pop-up widgets. However, there are two important methods that the pop-up widget can use to hint to the parent widget that it’s ready to be closed:

onExecute: function(){
    // summary: attach point for notification about when a menu item has been executed
},

onCancel: function(/*Boolean*/ closeAll){
    // summary: attach point for notification about when the user cancels the current menu
}

dijit/popup will monitor calls to these two methods and inform the parent widget when either of them is executed.

Here’s an example from a pop-up widget that triggers onExecute when it’s been clicked:

onItemClick: function(/*Widget*/ item, /*Event*/ evt){
    ...
    // before calling user defined handler, close hierarchy of menus
    // and restore focus to place it was when menu was opened
    this.onExecute();

    // user defined handler for click
    item.onClick(evt);
    ...
}

Lifecycle

The lifecycle of a pop-up widget looks like this:

  1. Parent widget calls popup.open to display the pop-up, passing onExecute and onCancel callbacks for when it needs to close
  2. User interacts with the pop-up, causing this.onExecute() or this.onCancel() to be called on the pop-up widget
  3. dijit/popup code notices the onExecute/onCancel method has been called and informs the parent widget by calling the onExecute function defined in the popup.open call
  4. Parent widget calls popup.close, which closes the pop-up
  5. popup.close calls the onClose callback defined in the original popup.open call

If the user clicks a blank section of the screen in order to close the pop-up instead of interacting with the widget, then the ending steps of the lifecycle are slightly different:

  1. dijit/popup code notices the click on the blank area of the screen
  2. dijit/popup code doesn’t close the pop-up widget directly, but rather calls the onCancel callback from the original popup.open call
  3. Parent widget calls popup.close, which closes the pop-up

Stacks

Pop-ups can open other pop-ups. This ability is leveraged heavily by dijit.Menu. To facilitate this, dijit/popup keeps track of the entire stack of open pop-ups. In the case when a hierarchy of pop-ups all need to be closed at once, calling popup.close on the top-most pop-up will close all child pop-ups. This means that parent widgets do not need to maintain their own stack of pop-ups in order to ensure that they can clean up properly after themselves.

Keyboard handling

dijit/popup automatically listens for key presses on the ESC key as a way to cancel the highest pop-up and return to the parent node (which may itself be a pop-up). When the ESC key is pressed, the onCancel callback passed in the call to popup.open is called. dijit/popup also listens for the TAB key, and if it sees it, the entire stack of pop-ups is cancelled (in the case of menus, where one pop-up has opened another and so forth).

Note that in neither of these cases does the dijit/popup code directly close any pop-ups. It just calls the onCancel callback defined in the call to popup.open. That callback then is responsible for calling popup.close(popupWidget).