Working with Controls

The Oracle JET framework includes buttons, menus, and container components to control user actions or display progress against a task. For HTML elements such as simple lists, you can use the standard HTML tags directly on your page, and Oracle JET will apply styling based on the application's chosen theme.

For example, you can use the ojButton component as a standalone component or include in ojButtonset , ojMenu, and ojToolbar container components.

Navigation components such as ojConveyorBelt, ojFilmStrip, and ojTrain use visual arrows or dots that the user can select to move backward or forward through data.

To show progress against a task in a horizontal meter, you can use the ojProgressbar component.

The Oracle JET Cookbook and JavaScript API Reference for Oracle® JavaScript Extension Toolkit (JET) include complete demos and examples for using Oracle JET controls, and you may also find the following tips and tricks helpful.

Topics:

Working with Buttons

Use the Oracle JET ojButton component to display a push or toggle button. Oracle JET buttons are WAI-ARIA compliant and themable, with appropriate styles for hover, active, checked, and disabled.

  • Push button: Ordinary button that does not stay pressed when clicked

    You can configure push buttons as the HTML button element, anchor (<a>), or input element of type input, submit, or reset. In general, use the button element unless you need the anchor capability. Buttons using the input element (of any type) are less frequently used since they don't support icons.

    <button id= "button"
            data-bind="click: buttonClick,
                       ojComponent: { component: 'ojButton', label: 'A button element' }">
    </button>
    
    <a id="anchor" href="#last"
       data-bind="click: buttonClick,
                  ojComponent: { component: 'ojButton' }">An anchor</a>
    
    <input id="inputButton" type="button"
           data-bind="click: buttonClick, 
                      ojComponent: {component: 'ojButton', label: 'An input button'}"/>
    
  • Toggle button: Button that toggles between a selected state and an unselected state when clicked

    You can configure toggle buttons as the HTML input element of type radio or checkbox. The label must be a sibling of the input element and immediately precede it in order to ensure compatibility with Oracle JET's ojComponent binding. Also, the label's for attribute must refer to the input's id attribute.

    <div id='buttons-container'>
       <div id="advancedWrapper"
           data-bind="ojComponent: {component: 'ojButtonset', checked: isAdvanced}">
           <label for="advanced">Toggle</label>
           <input type="checkbox" id="advanced" value="Toggle"/>
       </div>
    </div>
    

    A given radio button must not be both checked and disabled, unless all radio buttons in the group are disabled, since this removes the entire radio group from the tab order in mainstream browsers. This issue applies to native radio buttons and is not unique to Oracle JET.

The Oracle JET Cookbook at Buttons includes complete examples for all buttons. In addition, the ojButton API documentation describes support for keyboard interaction, accessibility, event handling, pseudo-selectors for jQuery expressions, setting component state, and a comparison of Oracle JET buttons with jQuery UI buttons. In particular, you should make note of the following:

  • Register click handlers directly on the button, rather than on an ancestor.

    <button id= "button"
            data-bind="click: buttonClick,
                       ojComponent: { component: 'ojButton', label: 'A button element' }">
    </button>
    

    If you register the click handler on an ancestor, the click target could be removed if any of the button's DOM is swapped out. For example, if you're alternating the text and icon between Play and Pause, the event bubbling will stop if the click target was part of the content that was removed in the swap.

  • If you need to set an ojButton component's checked state programmatically, then wrap it in an ojButtonset so that you can use its checked option. It is OK for a button set to contain only one button.

Working with Button Sets

The ojButtonset component is a themable, visual and semantic grouping container for Oracle JET buttons that is also compliant with WAI-ARIA. Use ojButtonset to group related buttons, such as a group of radios or checkboxes.

Create the ojButtonset on a HTML container element, such as the div element. The Oracle JET cookbook at Button Sets contains the complete recipe to create the button set shown above.

Here are some tips for working with button sets:

  • A button set that contains radios should contain all radios in the radio group.

  • Checkboxes and radio buttons in the button set should specify the value attribute, since the checked option refers to that attribute.

  • The application should not do anything to interfere with the focus management. For example, it should not set the tabindex of the buttons.

  • Enabled buttons should remain user visible. Otherwise, the arrow-key navigation to the button will cause the focus to seemingly disappear.

  • The button set's focusManagement option should be set to none when placing the button set in an ojToolbar component.

  • The application is responsible for applying WAI-ARIA aria-label and aria-controls attributes to the button set, as appropriate.

    aria-label="Choose only one.  Use left and right arrow keys to navigate."
    aria-controls="myTextEditor"
    
  • If the checked option and DOM get out of synch (for example, if a set of buttons contained in a button set changes, possibly due to a Knockout binding), then the application is responsible for updating the checked option.

  • The application doesn't need to listen for the optionChange event, since the ojComponent checked binding will update the bound observable whenever the checked state changes.

For additional information about the ojButtonset component's options, events, and methods, see the ojButtonset API documentation.

Working with Conveyor Belts

The Oracle JET ojConveyorBelt component manages a group of sibling child elements to control the number of child elements displayed and provides horizontal or vertical scrolling to cycle through the other child elements.

Define the ojConveyorBelt on the HTML div element. You can add the sibling child elements as either direct children of the conveyor belt or as the children of a container element which is the direct child of the conveyor belt. In this example, the ojConveyorBelt is configured for horizontal scrolling with a maximum width that varies on the screen width, and the sibling child elements are defined as Oracle JET ojButton components.

<div id="conveyorbelt-horizontal-example">
  <div class="oj-flex">
    <div class="oj-lg-6 oj-md-9 oj-sm-12"
         data-bind="ojComponent: {component: 'ojConveyorBelt'}">
      <button data-bind="ojComponent: {component: 'ojButton'}">Hydrogen</button>
      <button data-bind="ojComponent: {component: 'ojButton'}">Helium</button>
      <button data-bind="ojComponent: {component: 'ojButton'}">Lithium</button>
      <button data-bind="ojComponent: {component: 'ojButton'}">Beryllium</button>
      <button data-bind="ojComponent: {component: 'ojButton'}">Boron</button>
      <button data-bind="ojComponent: {component: 'ojButton'}">Carbon</button>
      <button data-bind="ojComponent: {component: 'ojButton'}">Nitrogen</button>
      <button data-bind="ojComponent: {component: 'ojButton'}">Oxygen</button>
      <button data-bind="ojComponent: {component: 'ojButton'}">Fluorine</button>
      <button data-bind="ojComponent: {component: 'ojButton'}">Neon</button>
      <button data-bind="ojComponent: {component: 'ojButton'}">Sodium</button>
      <button data-bind="ojComponent: {component: 'ojButton'}">Magnesium</button>
    </div>
  </div>
</div>

Note:

The ojConveyorBelt component does not provide accessibility features such as keyboard navigation. It is the responsibility of the application developer to make the items in the conveyor belt accessible. For tips and additional detail, see the ojConveyorBelt API documentation.

When you configure the child elements as direct children of the ojConveyorBelt, the component will ensure that they are laid out according to the specified style. If, however, you configure the child elements as the children of a container element, you must take additional steps to ensure the correct display. For details, see the ojConveyorBelt API documentation.

The Oracle JET Cookbook Conveyor Belts demos contain the complete code for this example. In addition, you will find examples for a vertical conveyor belt and conveyor belts with nested content, tab-based scrolling, and programmatic scrolling.

Note:

The Oracle JET ojFilmStrip component also manages a group of sibling child elements to provide horizontal or vertical scrolling to cycle through the other child elements. However, it also provides the ability to:

  • lay out a set of items across discrete logical pages.

  • control which and how many items are shown.

  • hide items outside the current viewport from tab order and screen readers.

For additional information, see Working with Film Strips.

Working with Film Strips

The Oracle JET ojFilmStrip component manages a group of sibling child elements to lay out its children in a single row or column across logical pages and provides horizontal or vertical scrolling to cycle through the other child elements. You can configure the film strip to use arrows or add the ojPagingControl component which uses dots for scrolling through the child elements.

The following image shows two ojFilmStrip components configured for horizontal scrolling, The sibling child elements are panels, using the Oracle JET panel design pattern. In the top film strip, the user selects arrows for navigating through the content, and the user selects dots for navigating through the bottom film strip content.

Configuring Film Strips

Define the ojFilmStrip on the HTML div element and add the sibling child elements as direct children of the film strip. The code sample below shows the markup for the film strip example using arrows for navigation.

<div id="filmStripDiv" class="oj-panel" style="margin: 20px;">
  <div id="filmStrip" aria-label="Set of chemicals"
       data-bind="ojComponent: {component: 'ojFilmStrip'}">
  <!-- ko foreach: chemicals -->
  <div class="oj-panel oj-panel-alt2 demo-filmstrip-item"
       data-bind="style: {display: getItemInitialDisplay($index())}">
    <span data-bind="text: name"></span>
  </div>
  <!-- /ko -->
  </div>
</div> <!-- end filmStripDiv -->

You can use the arrowPlacement option to control the location of the arrows. By default, it is set to adjacent which displays arrows outside the content, but you can set it to overlay to overlay the arrows on the content.

In this example, the film strip uses the Knockout foreach binding to iterate through the list of chemicals defined in the application's main script, shown below.

require(['ojs/ojcore', 'knockout', 'jquery', 'ojs/ojknockout', 'ojs/ojfilmstrip'],
function(oj, ko, $)
{
  $(document).ready(
    function()
    {
      function MyModel() {
        var self = this;
        self.chemicals = [
          { name: 'Hydrogen' },
          { name: 'Helium' },
          { name: 'Lithium' },
          { name: 'Beryllium' }
          { name: 'Boron' },
          { name: 'Carbon' },
          { name: 'Nitrogen' },
          { name: 'Oxygen' },
          { name: 'Fluorine' },
          { name: 'Neon' },
          { name: 'Sodium' },
          { name: 'Magnesium' }
        ];

        getItemInitialDisplay = function(index)
        {
          return index < 3 ? '' : 'none';
        };
      };
       
      var model = new MyModel();
      
      ko.applyBindings(model, document.getElementById('filmStripDiv'));
    }
  );
});

ojFilmStrip will lay out the child items across multiple logical pages and allow for changing between logical pages. When the component is resized, the layout will adjust automatically, and the number of pages and items shown per page may change. To control the display when the page changes, use the ojFilmStrip component's getPagingModel() method.

The Oracle JET Cookbook at Film Strips includes the complete code for the example used in this section. You can also find examples for film strips with pagination, vertical film strips, lazy loading a film strip, film strips that contain master-detail data, and film strips that use the getPagingModel() to display paging information.

Note:

ojFilmStrip is a layout component, and it is the responsibility of the application developer to make the items in the film strip accessible. For tips and additional detail, see the Accessibility section in the ojFilmstrip API documentation.

Working with Menus

The ojMenu component is a themable, WAI-ARIA compliant menu with mouse and keyboard interactions for navigation. After you create the menu, you can add it as a menu option to an ojButton component to create a menu button, or add it as a context menu to an Oracle JET component or HTML5 element.

Topics:

Working with ojMenu

You can create an ojMenu component from any valid markup as long as the elements have a strict parent-child relationship and each menu item has an anchor. Typically, you create the menu from an unordered list, with menu items that contain anchors, which in turn contain the menu item text. When your menu is displayed on a small screen, such as on a mobile device, the menu will behave like a sheet menu, and its contents will slide up from the bottom of the screen.

The following code sample shows the markup used to create the basic menu. To handle menu selection, add a select listener.

<div id='menubutton-container'>
  <button id="menuButton"
            data-bind="ojComponent: {component: 'ojButton', label: 'Actions', 
                                   menu: '#myMenu'}">
  </button/>
  <!-- To handle menu item selection, use a select listener as shown, not a click listener. -->
  <ul id="myMenu" style="display:none"
      data-bind="ojComponent: {component: 'ojMenu', select: menuItemSelect}">
    <li id="zoomin">
      <a href="#"><span class="oj-menu-item-icon oj-fwk-icon oj-fwk-icon-arrow-n"></span>Zoom In</a>
    </li>
    <li id="zoomout">
      <a href="#"><span class="oj-menu-item-icon demo-icon-font demo-bookmark-icon-16"></span>Zoom Out</a>
    </li>
    <li id="divider"></li>
    <li id="save">
      <a href="#"><span class="oj-menu-item-icon demo-icon-font demo-palette-icon-24"></span>Save</a>
    </li>
    <li id="print" class="oj-disabled">
      <a href="#"><span class="oj-menu-item-icon demo-icon-font demo-chat-icon-24"></span>Print...</a>
    </li>
  </ul>
  <p class="bold">Last selected menu item:
    <span id="results" data-bind='text: selectedMenuItem'></span>
  </p>
</div>

The following script defines the selection listener.

require(['ojs/ojcore', 'knockout', 'jquery', 'ojs/ojknockout', 'ojs/ojmenu'],
function(oj, ko, $)
{ 
  function MenuModel() {
    var self = this;
    self.selectedMenuItem = ko.observable("(None selected yet)");
    self.menuItemSelect = function( event, ui ) {
        self.selectedMenuItem(ui.item.children("a").text());
    };
}

$(function() {
    ko.applyBindings(new MenuModel(), document.getElementById('menubutton-container'));
});
});

For additional information about the ojMenu component's options, events, and methods, see the ojMenu API documentation.

The Oracle JET cookbook includes advanced examples for working with ojMenu, including demos for working with sub-menus and templates. For details, see Menu (Advanced).

Working with Menu Buttons

Menu buttons are ojButton components that display an ojMenu component when the user does one of the following:

  • Clicks on the button.

  • Sets focus on the button and presses the Enter, Spacebar, or Arrow Down key.

To create the menu button, add the basic ojMenu component as a menu option to an ojButton component configured on button or anchor tags. In the markup, place the ojMenu markup immediately after the ojButton markup.

The following code sample shows the markup for the menu button, with the details for the basic menu omitted.

<div id='menubutton-container'>
  <button id="menuButton"
          data-bind="ojComponent: {component: 'ojButton', label: 'Actions', 
                                   menu: '#myMenu'}">
  </button>
  <ul id="myMenu" style="display:none"
      data-bind="ojComponent: {component: 'ojMenu', select: menuItemSelect}">
    <li id="zoomin">
      <a href="#"><span class="oj-menu-item-icon oj-fwk-icon oj-fwk-icon-arrow-n"></span>Zoom In</a>
    ... contents omitted
  </ul>
  <p>
  <p class="bold">Last selected menu item:
    <span id="results" data-bind='text: selectedMenuItem'></span>
  </p>
</div>

The following code sample shows the code that initializes the menu button.

require(['ojs/ojcore', 'knockout', 'jquery', 'ojs/ojknockout', 'ojs/ojbutton', 'ojs/ojmenu'],
function(oj, ko, $)
{

function MenuModel() {
    var self = this;
    self.selectedMenuItem = ko.observable("(None selected yet)");
 
    self.menuItemSelect = function( event, ui ) {
        self.selectedMenuItem(ui.item.children("a").text());
    };
}

$(function() {
    ko.applyBindings(new MenuModel(), document.getElementById('menubutton-container'));
});

});

The Oracle JET Cookbook includes the complete code sample for the menu button shown in this section. For details, see Menu Buttons.

Working with Context Menus

Context menus are ojMenu components placed on an Oracle JET component or an HTML5 element using the contextmenu attribute. The element on which the context menu binding is placed should be user-focusable, for keyboard accessibility through the Shift+F10 key, since focus is returned to the element when the menu is dismissed.

In this example, the ojMenu component is placed on an ojButton component and the HTML anchor element. The code sample below shows the markup for the ojButton component and the HTML anchor element, with the details for the basic menu omitted.

<div id="button-container">
    <h3>A JET component with a context menu:</h3>
    <!-- Use the HTML5 contextmenu attribute for JET components -->
    <button id= "myButton" contextmenu="myMenu"
            data-bind="ojComponent: { component: 'ojButton',
                                      label: 'Right-click me. Shift-F10 me. Press and hold me.' }">
    </button>
    <h3>An ordinary HTML element with a context menu:</h3>
    <!-- Use the ojContextMenu binding for elements that aren't JET components 
         The tabindex makes this div user-focusable per the requirements.-->
     <div id="myDiv" contextmenu="myMenu" tabindex="0"
        data-bind="ojContextMenu: {}">Right-click me. Shift-F10 me. Press and hold me.</div>  

    <!-- To handle menu item selection, use a select listener as shown, not a click listener.-->
    <ul id="myMenu" style="display:none" aria-label="Order Actions"
       data-bind="ojComponent: {component: 'ojMenu', select: menuItemSelect}">
        <li id="zoomin">
          <a href="#">oj-menu-item-icon oj-fwk-icon oj-fwk-icon-arrow-n></span>Zoom In</a>
        </li>
        <li id="zoomout">
          <a href="#">oj-menu-item-icon demo-icon-font demo-bookmark-icon-16></span>Zoom Out</a>
        </li>
        <li id="divider"></li> 

    ... contents omitted
    </ul> 
    <h3>Results:</h3> 
    <p class="bold">Last selected menu item in the button's context menu:
    <span id="buttonResults" class="italic" data-bind="text: selectedItem.myButton"></span>
    </p>
    <p>Last selected menu item in the div's context menu:
      <span id="divResults" class="italic" data-bind="text: selectedItem.myDiv"></span>
    </p>
</div>

When you add a context menu to an Oracle JET component, you apply the ojComponent binding as shown above. If you add the context menu to an HTML5 element, use the ojContextMenu binding, also shown above.

The following code sample shows the code to initialize the context menu.

require(['ojs/ojcore', 'knockout', 'jquery', 'ojs/ojknockout', 'ojs/ojbutton', 'ojs/ojmenu'],
function(oj, ko, $)
{
function MenuModel() {
  var self = this;
  self.selectedItem = {
       myButton: ko.observable("(None selected yet)"),
       myDiv: ko.observable("(None selected yet)")
  };
  
  self.menuItemSelect = function( event, ui ) {
       var launcherId = $(event.target).ojMenu("getCurrentOpenOptions").launcher.attr("id");
       self.selectedItem[launcherId](ui.item.children("a").text());
  };
}

$(function() {
  ko.applyBindings(new MenuModel(), document.getElementById('button-container'));
});

});

The Oracle JET cookbook contains the complete example, including the CSS for the menu icons, at: Context Menus.

Working with Progress Indicators

You can use ojProgressbar to indicate progress against a task in a horizontal meter. Set the value for the progress indicator in the ojProgressbar value option. In the image below, the progress indicator's value option is set to 70 to indicate that the task is 70% complete.

To indicate that the value is indeterminate, set the value option to -1, and the progress indicator will change to reflect the indeterminate status.

To create the ojProgressbar component, you can use the ojComponent binding with Knockout's data-bind syntax.

<div id="progressbarWrapper">
  <div id="progressbar" data-bind="ojComponent:{component: 'ojProgressbar', value: progressValue}">
  </div>
</div>

The script that sets the value defines a Knockout observable and sets the initial value. In this example, the progress indicator's initial value is set to -1, to indicate that the value is indeterminate.

require(['ojs/ojcore', 'knockout', 'jquery', 'ojs/ojknockout', 'ojs/ojprogressbar'],
  function(oj, ko, $)
  {
    function ViewModel()
    {
      var self = this;
      self.progressValue = ko.observable(-1);
    }

    ko.applyBindings(new ViewModel(), document.getElementById('progressbarWrapper'));
  });

The Oracle JET Cookbook at Progress Indicators contains a complete example for an ojProgressbar that shows the effect of adjusting the progress indicator's value. You can also find examples that show a progress indicator with labeling and a progress indicator that is linked to changing data.

Working with Tags

You can add HTML tags to your Oracle JET page as you would for any other HTML application. However, you should be aware that Oracle JET provides styling directly on the following tags:

  • Header (h1, h2, h3, h4)

  • Horizontal rule (hr)

  • Link (a)

  • List (ul, ol, li)

  • Paragraph (p)

There may be use cases where you do not want to use aspects of the default theming because it causes compatibility issues. For example, you may be embedding JET components or regions in a page controlled by another technology, such as Oracle ADF. In these cases, Oracle JET provides options for theming for compatibility. For additional information, see Understanding Oracle JET Theming For Compatibility.

Working with Toolbars

The ojToolbar component is a WAI-ARIA compliant toolbar, with arrow key navigation and a single tab stop. The tab stop updates on navigation, so that tabbing back into the toolbar returns to the most recently focused button.

The ojToolbar component can contain ojButton and ojButtonset components as well as non-focusable content such as separator icons.

Here are some tips for working with toolbars:

  • A toolbar that contains radio buttons should contain all radio buttons in the radio group.

  • The application should not do anything to interfere with the focus management.

  • Enabled buttons should remain user visible. Otherwise, the arrow-key navigation to the button would cause the focus to seemingly disappear.

  • The button set's focusManagement option should be set to none when placed in a toolbar.

The Oracle JET Cookbook includes toolbar examples at Toolbars. For additional information about the ojToolbar component's options, events, and methods, see the ojToolbar API documentation.

Working with Trains

The ojTrain component displays a navigation visual that enables the user to move back and forth between different points. Typically, the train displays steps in a task or process.

Each step can display information about its visited state (visited, unvisited, or disabled) and a message icon of type confirmation, error, fatal, warning, or info.

You can create the ojTrain component on the HTML div element. Use the Knockout data-bind syntax to define the ojTrain component and any desired options. The code sample below shows a portion of the markup for the first ojTrain shown in this section.

<div id="train-container" >
  <div id="train"
       data-bind="ojComponent:{component: 'ojTrain', selected: currentStepValue, steps: stepArray}">
  </div>
  ... contents omitted
</div>

The code sample below shows the code that applies the binding, defines the steps and captures the step selection.

require(['ojs/ojcore', 'knockout', 'jquery', 'ojs/ojknockout', 'ojs/ojtrain', 'ojs/ojbutton'],
function(oj, ko, $)
{
  function TrainData() {
    this.currentStepValue = ko.observable('stp1');
    this.stepArray = 
      ko.observableArray(
        [{label:'Step One', id:'stp1'},
         {label:'Step Two', id:'stp2'},
         {label:'Step Three', id:'stp3'},
         {label:'Step Four', id:'stp4'}, 
         {label:'Step Five', id:'stp5'}]);
  };
 
  var trainModel = new TrainData();
 
  $(function() {
    ko.applyBindings(trainModel, document.getElementById('train-container'));
  });
});

The Oracle JET Cookbook includes the complete code for this example at Trains. You can also find additional examples that show a stretched train, a train with messages, and a train with button navigation.