Wednesday, July 20, 2016

Using jQuery Interactions with Oracle JET

Draggable, droppable, resizable, selectable, and sortable are jQuery UI interactions that you may want to use when building custom Oracle JET applications. The question is, "How?" Here are three steps:

  1. Find the jQuery UI interaction plugin file,
  2. Import the interaction file into a module (declare it as a dependency), and
  3. Attach the interaction to a component.

Caveat: even though jQuery UI is one of Oracle JET's dependencies, Oracle JET uses only a small subset of the jQuery UI library. With that in mind, this post will describe how to use draggable and droppable with Oracle JET. Just be careful when using jQuery UI interactions with Oracle JET components because JET components weren't designed to be manipulated in this manner. Nevertheless, jQuery UI's interactions are so polished, it is worth a try.

Identify the jQuery UI Interaction File

This sounds like the easy part. Since jQuery UI is one of Oracle JET's dependencies, bower will install it automatically. Depending on how you installed Oracle JET, however, finding jQuery UI files may be difficult (see this thread). If you add Oracle JET to your project through the Bower command (bower install oraclejet --save), Bower will download all of jQuery UI and you will find each jQuery UI component inside your bower components folder (usually bower_components). Since the Oracle JET Yeoman generator also uses bower, the generator will also download all of jQuery UI into your bower components folder. But here is where it gets a little tricky. After Bower finishes, the Yeoman generator will move Oracle JET's real dependencies into /js/libs. A quick review of the files in /js/libs show that certain files, such as droppable, are missing. They are still in the bower_components folder, just not in the jQuery UI location identified in the Oracle JET RequireJS configuration. For Yeoman template users, this can be a little problematic since the RequireJS configuration already contains a declaration for jQuery UI, but that declaration doesn't include every jQuery UI file. For others that are using Bower directly, this is a non-issue. Your Oracle JET RequireJS configuration already points to jQuery UI and that location contains ALL jQuery UI files including source, minified, and combined files. So for bower users, "carry on." Yeoman users will want to copy the appropriate interaction file into the jQuery UI folder identified by the RequireJS configuration.

Import the Interaction File into a Module

Whether your ViewModels are pure knockout components or ojModules, chances are high you are using AMD-style modules through RequireJS. We need to tell RequireJS how to find our interaction plugin. jQuery UI interaction plugins are jQuery plugins, so we will want to import jQuery as well. Here is a sample AMD define block that references draggable and droppable from the standard Oracle JET RequireJS configuration location:

define([
  'jquery',
  'jqueryui-amd/draggable',
  'jqueryui-amd/droppable'
], function($) {

Attach the Interaction to a Component

Let's say we have a list of DOM elements that are supposed to be draggable and a couple more DOM elements that are supposed to be drop targets (droppable). Both draggable and droppable elements need to be enhanced by jQuery UI. Through CSS class selectors, etc, identifying those DOM elements should be trivial. In the asynchronous world of Knockout and Single Page Applications (SPA), the hard part is knowing when those DOM elements will exist. Can't we use $(document).ready? Maybe, but don't count on it. In an SPA, $(document).ready may have fired several views ago. Furthermore, the draggable elements may come from an asynchronous service, which means they may not exist at page load. Instead, we need DOM elements with lifecycle management events. For each enhanced DOM node, we need to know when that DOM node is available. Knockout gives us lifecycle management capability through custom bindings. I have written about ko.bindingHandlers on many occasions. What makes this example different is that it is very simple. Whereas others required init and update handlers, these interactions require only an init handler. Here are example ko.bindingHandlers implementations for draggable and droppable::

ko.bindingHandlers.jmDraggable = {
  init: function(element) {
    $(element)
      .draggable({
        revert: 'invalid',
        helper: "clone"
      });
  }
};

ko.bindingHandlers.jmDroppable = {
  init: function(element) {
    $(element)
      .droppable({
        drop: function(event, ui) {
          $(ui.draggable)
            .detach()
            .css({
              top: 0,
              left: 0
            })
            .appendTo($(this));
        }
      });
  }
};

When implementing a custom binding handler, you are creating your own custom knockout binding. You want to make sure your binding names don't collide with other binding names. With that in mind, I used the jm prefix to distinguish my bindings from other people's bindings. I would then use these bindings in HTML that looked something like this:

<div id="panelPage">
  <div class="oj-flex drag-items draggables oj-margin oj-padding"
       data-bind="jmDroppable, foreach: {data: labels, as: 'label'}">
    <div class="oj-panel oj-margin" data-bind="jmDraggable, css: label">
        <span data-bind="text: label"></span>
    </div>
    
  </div>
  
  <div class="drop-target oj-margin oj-padding"
       data-bind="jmDroppable">
    <span>Drop items here</span>
  </div>
  
</div>

Here is a working example that makes oj-panel draggable:

Tuesday, June 21, 2016

Creating Relational Views with Oracle JET (... or Passing Parameters to Child Views)

When building composite user interfaces, how do you share data between nested views? Nested views are a key element of modular applications. I recently gave advice for determining when to use Modular Views in Knockout with Oracle JET. When breaking a user interface into reusable components, a developer has to consider the relationships between data within those user interface fragments. The WorkBetter Oracle JET Sample application is an example of a modular user experience that shares information between parent and child views. In the WorkBetter example, the sharing is between the main container "root" view and route-related views. Here is a list of ways we can share information between views:

  • Context variables such as $parent, $parents, and $root;
  • Global AMD/RequireJS modules; or
  • Parameters (knockout components or ojModule)

Context Variables ($parent, $parents, and $root)

This is a common approach because of its simplicity. If you are writing a child View and you know the structure of the parent View, then why not just reference the parent context through $parent?

I really, really don't like this option. Before I tell you why, I want to make this clear up front:

There is nothing wrong with $parent or any other context variable.

I use context variables such as $parent all the time inside a single view to reference hierarchical contexts within that same view. What I don't like is using context variables to reference a higher scope outside the current View and ViewModel. Here is why:

Referencing ancestor ViewModels from a child ViewModel creates an implicit, unwritten contract between a child ViewModel and its ancestors.

Any changes to the parent ViewModel will have an impact on the child ViewModel and there is nothing in the parent View or ViewModel alerting other developers to this relationship.

Global AMD/RequireJS Modules

This method has some merit. I use it for sharing configuration-like information, information that is common to the entire application, not view specific. The benefit of this alternative is that it is the least coupled. What makes this approach suboptimal, however, is that we are using globals to pass values when globals are not necessary. Every module has an opportunity to interact with a global variable. This approach is sort of like having a private conversation by pinning messages to a global message board knowing that anyone can read and change the message anytime.

Besides the potential for eavesdropping, I discourage this approach because it does nothing to document the contract between related ViewModels. By definition, there is a relationship, but the relationship is hidden by the use of globals. At least the Context Variables approach identified the relationship through the use of Context Variables.

When using globals in this manner, be careful with the module's exposed interface. Don't allow writing to a variable that should be read only and watch for side effects. Although effective for sharing between ViewModels, there are much better ways.

Parameters

This is my favorite option because it explicitly defines the relationship between ViewModels. The parent determines what data to share with the child view and explicitly passes that data through the params attribute. The child ViewModel explicitly identifies its params through its ViewModel constructor. Here is an example of a parent View that uses the params attribute to share data with a child ViewModel:

<div class="oj-flex oj-margin">
  <!-- ko foreach: {data: employees, as: 'emp'} -->
  <div data-bind="ojModule: { name: 'gMMqrR',
                  params: emp }">
  </div>
  <!-- /ko -->
</div>

The parent View clearly defines emp as data to share with a child ViewModel. Here is the child ViewModel:

define(['knockout'], function(ko) {
  'use strict';

  var ViewModel = function(employee) {
    var self = this;
    self.employee = employee;
  };

  ViewModel.prototype.selectEmployee =
    function(data, event) {
      console.log("You selected", data.employee.name);
    };

  return ViewModel;
});

The child ViewModel's constructor parameter clearly identifies its data requirements. Here is the codepen if you are interested in fiddling with this solution:

See the Pen Oracle JET 2.0.1 ojModule Params by Jim Marion (@jimj) on CodePen.

Here is the child ojModule codepen:

See the Pen Oracle JET 2.0.1 ojModule Params (submodule) by Jim Marion (@jimj) on CodePen.

Keeping with the best practice identified in Modular Views in Knockout and Oracle JET, I used a child module to encapsulate event handlers within a scope change. This example is rather simplistic with its small View and ViewModel, so ojModule may be overkill. Let's think about what this view would look like if I had not used a separate module. Here is the combined view:

<div class="oj-flex oj-margin">
  <!-- ko foreach: {data: employees, as: 'emp'} -->
  <div class="oj-panel oj-margin"
      data-bind="click: $parent.selectEmployee">
    <i data-bind="text: emp.name"></i>
  </div>
  <!-- /ko -->
</div>

This is not that exciting or unique really. Notice that I had to use $parent in the View. This is a perfectly acceptable use of a context variable. $parent in this scenario allows us to access an event handler method at a higher context than the current context. Now imagine a much larger scenario where you have lots of foreach constructs and related event handlers. Using ojModule to keep handlers directly related to their views within submodules may make code easier to read and comprehend.

→ BEGIN RABBIT TRAIL

The child codepen above demonstrates one more important practice: defining functions as few times as possible. The ViewModel module for the child ojModule defines the selectEmployee click handler as a prototype method rather than defining the function inside the constructor. It may be more common in knockout to use constructor defined functions as follows:

var ViewModel = function(employee) {
  var self = this;
  self.employee = employee;
  self.selectEmployee = function() {
    console.log("You selected", self.employee.name);
  };
};

The problem with this code is that it defines a new self.selectEmployee function for each employee (each iteration of the ko foreach). This would create one new instance of the function object for each element in the array. Think of the performance impact! When using embedded modules in loops, this is an important consideration. This is a key difference between child modules and standard navigational modules and something to consider when creating child modules.

Another way to write this is to use private functions. Here is the same ViewModel, but using a private function definition:

define(['knockout'], function(ko) {
  'use strict';

  var selectEmployee = function(data, event) {
    console.log("You selected", data.employee.name);
  };

  var ViewModel = function(employee) {
    var self = this;
    self.employee = employee;
    self.selectEmployee = selectEmployee;
  };

  return ViewModel;
});

Either add to the prototype or use a private function OUTSIDE the constructor. I'm not sure it matters. The important point is to minimize creating functions inside loops.

← END RABBIT TRAIL

Passing Methods to Child Modules

Within our ojModule example, let's say we want to track the selected component at the root level. How would you notify the root ViewModel that the selection changed? One way is to pass a callback (or an observable) as a parameter to the child ojModule. Here is what the new View would look like:

<div class="oj-flex oj-margin">
  <!-- ko foreach: {data: employees, as: 'emp'} -->
  <div data-bind="ojModule: { name: 'XKNNPw',
                  params: {
                      employee: emp,
                      onselect: $parent.selectEmployee
                  } }"
       class="employee">
  </div>
  <!-- /ko -->
</div>
<h2>Selected data</h2>
<pre data-bind="text: ko.toJSON(selectedEmployee, null, 2)">

Notice that I again used $parent inside my View to reference a higher scope. Just to make sure I'm clear, there is nothing wrong with using $parent to reference a higher scope within the same View. $parent only becomes problematic when referencing scopes beyond the current View.

Here is the parent/root ViewModel that defines the selectEmployee method.

  var ViewModel = function() {
    var self = this;

    self.employees = employees;

    // stores selected employee
    self.selectedEmployee = ko.observable({});

    // click handler for submodule
    self.selectEmployee = function(employee) {
      self.selectedEmployee(employee);
    };
  };

... and the child module ViewModel:

define(['knockout'], function(ko) {
  'use strict';

  var ViewModel = function(params) {
    var self = this;
    self.employee = params.employee;
    self.clickHandler = params.onselect;
  };

  return ViewModel;
});

Click an employee in the list below and watch the Selected Data region change. Hint: use the tab key to move between items and the enter or space key to select items.

See the Pen Oracle JET 2.0.2 ojModule Function Params by Jim Marion (@jimj) on CodePen.

Oracle JET 2.0.2 Released

The Oracle JET team is doing an amazing job releasing new features and fixes with another release announced yesterday. With that announcement, I created new "base" versions of the Oracle JET CodePen and jsFiddle.

Monday, June 20, 2016

Oracle JET with CodePen

I was quite comfortable with jsFiddle as a playground and testing site for simple Oracle JET samples. As I moved onto ojModule and ojRouter, which require multiple files, I found jsFiddle somewhat limiting. There may be a way to create fiddles on fiddles, but I haven't found it. While considering how to build ojModule examples in jsFiddle, I stumbled upon this online roundup of code playgrounds which got me thinking about CodePen. Specifically, I was intrigued by the 10 Cool Things You Can Do with CodePen and JavaScript. For example, I can create a CodePen that has JavaScript and HTML and then never run it (View and ViewModel), but instead reference each by URL from another CodePen (one that defines an ojModule). Being able to create a CodePen JavaScript file that I can reference from other CodePens also means I can move the RequireJS configuration into a single file and reference it from other CodePens, eliminating the RequireJS/OJet configuration noise from my examples. This allows me to focus on just the important stuff (the delta).

One other concern I had with jsFiddle is finding fiddles. CodePen allows for tags which means I can Search for all CodePens tags with oraclejet.

With these issues in mind, I ported my Oracle JET Base 2.0.1 Debug fiddle to CodePen. Unlike my prior jsFiddles, these CodePens only contain the "delta" code necessary to implement a solution. The RequireJS configuration is visible from the pen's JavaScript configuration, but is now in a separate pen. Likewise, I no longer have to import the CSS but reference it in the pen's CSS settings. Before becoming familiar with CodePen, I found these "invisible" dependencies confusing. Now that I understand CodePen, I find them really helpful because they allow me to remove the configuration noise and focus on the pen's main idea.

Relevant CodePens

Thursday, June 16, 2016

A Sassy Oracle JET Yeoman Generator (2.0.x)

As a consumer of the Oracle JET Yeoman Generator, one thing I noticed is that generated projects do not include a Sass compilation step. Here is how I enable Sass in a "Basic" Oracle JET Yeoman project. This is meant to be more of a Getting Started guide than a definitive reference. Since the following reference uses compass the first step is to install compass. This old article from the Sass Way should help you get Sass and Compass installed. After installing Compass open a terminal and navigate to your project's root directory. Within that directory, invoke the following command:

npm install grunt-contrib-compass --save-dev

With dependencies in place, it is time to add Sass to the Oracle JET build files. First, let's create a compass.js configuration. Create a new file in scripts/grunt/config named compass.js. To this new file, add the following compass configuration. Compass has many valuable options, but this is enough to get started:

/* jshint -W097, node: true */
"use strict";

module.exports = {
  options: {
    sassDir: 'styles',
    cssDir: '.tmp/styles',
  },
  app: {
    options: {
      cssDir: 'styles'
    }
  },
  server: {
    options: {
      sourcemap: true,
      cssDir: 'styles'
    }
  }
};

I made up the "app" and "server" target names myself. Feel free to name them whatever makes sense to you (for example, serve or release, etc). If you choose different names, however, remember them because you will reference them later.

The delivered Oracle JET Grunt file contains two primary tasks: serve and build. Let's work on the `grunt serve` task first. As you probably know, the serve task launches a web server, listens for changes to web files, and then reloads the running browser app when file changes are detected. The watch step of the serve task is responsible for triggering other steps and then reloading the browser's content. Open scripts/grunt/config/watch.js and modify it as follows:

module.exports =
{
  compass: {
    files: ['styles/{,**/}*.{scss,sass}'],
    tasks: ['compass:server']
  },
  // to watch for changes in file and to perform livereload
  livereload:
  {
    files:
    [
      "css/!(libs)/**/*.css",
      "js/!(libs)/**/*.js",
      "js/{,*/}*.js",
      "css/{,*/}*.css",
      "**/*.html",
      "styles/*.scss"
    ],

    options:
    {
      livereload: "<%= oraclejet.ports.livereload %>"
    }
  }
};

Specifically, add the compass section and then add the styles/*.scss entry to the files array. This tells grunt to run compass when styles/*.scss files change.

Now we need to make the serve task aware of the new compass step. Open scripts/grunt/tasks/serve.js and add "compass:server", to the tasks array. The tasks section should now appear as follows:

  var tasks =
  [
    "compass:server",
    "connect:" + target + "Server" + (disableLiveReload ? ":keepalive" : ""),
  ];

Test it out by creating an scss file in the styles folder and then invoking grunt serve. You should see the *.css complement of your scss file appear in the styles folder.

Let's move onto the build task. Open the scripts/grunt/config.copy.js file and add the following exclusions to the release.src array: "!styles/**/*.map", "!styles/**/*.scss". Finally, open the scripts/grunt/tasks/build.js file and insert the "compass:app" step into the tasks array. You can pretty much place it anywere ahead of the "copy:release" step. I chose right before the "uglify:release" step. Test your build script by invoking grunt build:release. If all is working, you are now ready to begin Styling Custom Components with Oracle JET.

For further information, I recommend Customizing an Oracle JET Theme Using Sass and the Oracle JET Getting Started Guide.

Tuesday, June 14, 2016

Modular Views in Knockout and Oracle JET

"I have a View and ViewModel and I'm wondering if I should break it into multiple child Views and ViewModels." This is a great question and one that I've asked myself many times. Here are my criteria:

  1. Can I divide my workload, allowing others to help me if I convert sections of a view into sub views? (avoid merge conflicts)
  2. Am I using scope-changing constructs such as ko foreach?
  3. Is my ViewModel (or view) over 100 lines?

Conflict: I suppose there are people that take great pleasure in resolving merge conflicts. I'm not one of them. I can't say that I'm a fan of any type of conflict. Merge conflicts fall into that same "conflict/resolution" bucket. If I am working on a project with a teammate and we both need to access the same view, then I may give great consideration to partitioning that view.

Scope: It is quite common to use ko foreach and other scope-changing constructs. Often I find myself iterating over a data set. For each element in that data set, it is given that I will have to respond to some type of event: click to delete a row, view details, and so on. It is at this point, when I'm writing the event handler, that I realize I have changed scope. I have 3 options:

  • Put my event handler at the root of my ViewModel and reference it using context variables ($page) and then try to figure out how to identify the current element (such as ko.dataFor(event.target)),
  • Enrich my child data model with event handler methods, or
  • Move the contents of the ko foreach into a new view and ViewModel.

I'm not fond of $parent and other context-related variables. It seems too easy to lose sight of the real scope and couples my solution in a manner I'm not sure I prefer. As an alternative, I often place the content of a ko foreach in a new view and ViewModel so that event handlers and other ViewModel methods can interact with my data without scope issues. This is sort of like a scope reset.

100 lines... OK, you may have to humor me with this one. I find 100 lines to be easy to comprehend. Once I go over this threshold, code becomes more difficult to follow. I can read 100 lines with three presses of the page down key. I can keep that all in my brain and understand it without much scrolling (I suppose you could say my internal page size is 3 pages?).

Styling Custom Components with Oracle JET SCSS Variables

In my post Extending Oracle JET Components Through Custom Bindings, I used CSS to move the ojInputText border from the input element to the ojInputText "root" element. One of my readers commented on my improper use of color values instead of SCSS variables. Great point! Oracle JET includes SCSS theme variables for color and style. Since my goal was to maintain the delivered Oracle JET styling, it is better to use the Oracle declared SCSS theme variables. Here is what that prior example would look like if I used Oracle JET's theme-specific SCSS variables:

// following three lines taken from oj-alta.scss
@import "../bower_components/oraclejet/dist/scss/alta/oj.alta.variables";
// note: this generates a very large css file and takes a while to compile.
// if you are just interested in the variables, you can cheat and comment out
// these two imports
@import "../bower_components/oraclejet/dist/scss/3rdparty/normalize/normalize";
@import "../bower_components/oraclejet/dist/scss/alta/oj.alta.widgets";

.content-container {
  margin: 10px;
}

/* icon CSS here */
.birthday-input:after {
    font: normal normal normal 14px/1 FontAwesome;
    content: "\f1fd";
    margin: 0 10px;
}

.birthday-input input {
    border: none;
    flex: 1;
}

.oj-inputtext.birthday-input {
    display: flex;
    flex-flow: row nowrap;
    align-items: center;
    background-color: $background3Color;
    border: 1px solid $border4Color;
}

Notice the import at the top of this code fragment. This is a relative path pointing to the Oracle JET SCSS files within the bower install directory. In my case I store scss in a "styles" subfolder of the root project folder, making this path a relative path from ./styles to ./bower_componnets.

This solution assumes that you have your project configured for SCSS (grunt tasks, etc). Be aware that SCSS is not part of the Yeoman generated Oracle JET build script. You can learn more about Oracle JET and SCSS in the document Customizing an Oracle JET Theme Using Sass

Unfortunately, I can't exactly show this in a jsFiddle because the SCSS in jsFiddle doesn't appear to support remote scss partials. I can, however, paste in the relevant oj.alta.variables and pretend that I am importing the real Alta variables. In the sample below, instead of modifying one of my prior examples, this is another iteration of the "ojInputText with animated clear button" that has better support for accessibility (you can now tab to the delete button if it is visible).

Friday, June 3, 2016

Oracle JET on Cloud 9

I really like the collaborative editing features of Cloud9 (c9), but can I use them to collaboratively build Oracle JET applications? C9 is sort of like Google Docs for developers, allowing multiple users to work on the same file at the same time. You can forget about painful merges with source code systems because c9 allows everyone to work on the same files at the same time. It also doesn't hurt that c9 gives full access to the command line and provides an amazing editing experience.

Given c9's command line and node support, I was pretty sure that following the Getting Started Guide (steps 1 - 3) would get me up and running in a matter of minutes. After a grunt build, you can open index.html, click the run button, and explore the QuickStart Template. But what about grunt serve and livereload? There really isn't any magic in Oracle JET, so the first step is to see if anyone else has connect and livereload working in c9. This Stackoverflow post has a lot of great information as does this c9 doc and this c9 example. Based on that information, we see that c9 runs apache httpd on port 80 and makes ports 8080, 8081, and 8082 available. Our goal is to get connect and livereload running on those last three available ports. As that Stackoverflow post noted, 8080 was in use because I used the run button inside c9 to launch my application. If you want c9's default run feature to work, then I suggest you use port 8081 for the server and port 8082 for livereload.

Now that we have some available ports, the next hurdle is getting Oracle JET's grunt file to use them. Fortunately, the Oracle JET engineers already considered this and included command line options for optional ports. The following command will launch a web server on port 8080 with livereolad on 8081:

grunt serve --serverPort=8080 --livereloadPort=8081

This will get our app running in dev mode, but unfortunately, it won't be accessible from outside the c9 VM. If you test launching your app with the URL http://[yourworkspacename]-[yourusername].c9users.io:8080/, you will see a nice c9 message telling you that nothing is running on 8080. If you try the same URL with port 8081, however, you will see that livereload is working and waiting.

With that in mind, our final hurdle is to get grunt serving our app on an address we can access outside the VM. Unfortunately, this isn't configurable and will require us to change one line in the Oracle JET grunt configuration scripts. Within the scripts directory of your project, navigate to grunt/config and open connect.js. Inside the devServer options, right about line 14, you will see hostname. Just delete the contents of that string (should be localhost). Don't comment out the line, because that causes livereload to misbehave. The hostname option should now look like this:

hostname: "",

From the c9 terminal window, relaunch grunt serve using the command supplied above and test your project URL (http://[yourworkspacename]-[yourusername].c9users.io:8080/). You should be greeted by a fully functional QuickStart template that reloads when you modify and save files within your project. Now go and build something amazing!

Friday, May 27, 2016

Removing an Oracle JET Component from the Tab Order

A customer recently asked me if I could create a "quick entry" form that excluded certain fields from the regular tab order. Oracle JET input components have a tab index for a reason. They are designed for accessibility which means they work with accessible input devices and don't require a mouse. Removing data entry fields from the tab order means I have to use a pointing device, such as a mouse or tap, to select a skipped field. Although this goes against my better judgement, I understand the use case. If you are entering information in rapid, data entry mode, you don't want to tab over fields you rarely use. The issue I ran into is this:

How do you remove the tab index from certain Oracle JET components?

Input elements such as ojInputDate display a native HTML element and will automatically be part of the tab order. We can easily remove these elements from the tab order by setting the tabIndex to -1 like this:

<input tabindex="-1" data-bind="ojComponent: {
                    component: 'ojInputDate', value: selectedDate}" />

Other elements, such as ojSelect, use a clever collection of non-input HTML elements to capture input. For accessibility reasons, Oracle JET adds tabindex="0" to these input elements to ensure accessible devices can enter data. Since many of these Oracle JET elements begin life as a real HTML input element (input, select, etc), one might think that changing the tab index would be as easy as setting the tab index on the original input element. Unfortunately, it is not that easy. Another idea is to include tabIndex in the rootAttributes collection of an OJ component. Unfortunately, that doesn't work either. To remove these elements from the tab order, we must first identify the element with a tab index, and then change the value of the tab index. To do this effectively, we have to answer two questions:

  1. How do I identify the element with a tabIndex attribute?
  2. Timing wise, when will the DOM be ready for me to change the tabIndex?

Let's start with question #1. Study the following structure screenshot for a moment.

In the above screenshot, the JET generated oj-select is highlighted at the top. The very next element, the oj-select-choice element is the element with the tabIndex and is a child element of the oj-select. This is the element we want to modify and we need to find a way to programatically identify this element. Notice that the original select element is a sibling of the generated oj-select element. We could use a sibling selector. Sibling selectors are great for collections, where you want to style elements differently based on their position in a collection, but a sibling selector makes me a little nervous in this instance. I'm not sure we can depend on the sibling relationship identified in this screenshot. Rather than use a sibling selector, we can use Oracle JET's getNodeBySubId method. For Oracle JET components that are composed of several elements, we can identify individual pieces of the component by Sub ID. You can find the list of valid ojSelect Sub IDs here. We specifically want to select the oj-select-choice node. Unfortunately, oj-select-choice is not a node with a known Sub ID. If I expanded the oj-select-choice node in the structure screenshot, you would see that oj-select-chosen is a direct descendant of oj-select-choice. The oj-select-chosen node is selectable by Sub ID. With a little jQuery, we can easily traverse from oj-select-chosen up to oj-select-choice. We can test this by selecting our select element in the structure browser and then entering the following into the console:

$($0)
  .ojSelect( "getNodeBySubId", {'subId': 'oj-select-chosen'} )
  .closest( ".oj-select-choice" )

The following screenshot shows the results of that command (notice I also expanded the oj-select-choice to reveal the child oj-select-chosen).

A quick word about jQuery traversal methods... Using jQuery, there are often multiple ways to solve the same problem. In this situation we could either use the parents() or closest() methods to work our way up the hierarchy. Parents and Closest are similar, but, as the docs say, "The differences between the two, though subtle, are significant." We want to find the most immediate ancestor matching a selector. Closest accomplishes this. It identifies the match and then stops. The parents method, on the other hand, finds all matches and returns them as a collection. We have no need to walk the entire document hierarchy, so closest is the appropriate choice for this scenario. We have now answered question #1: How do I identify the element with a tabIndex attribute?

Next we need to handle the Life Cycle Management issue: How do we know when the ojSelect is available in the DOM (question #2)? Even though ojModule has Life Cycle Management events that tell us when the DOM is available, I don't suggest using them for this specific scenario. ojModule LCM events will work just fine with DOM elements that are hard coded into the view, but I'm not sure we should count on them for dynamically generated elements, such as those bound to an ko.observableArray. A better approach is to use a component-specific life cycle management approach such as custom bindings (ko.bindingHandlers). This allows us to manipulate an element as soon as it appears in the DOM. Here is an example ko.bindingHandler:

ko.bindingHandlers.inaccessibleOjSelect = {
  init: function(element, valueAccessor, allBindingsAccessor, ctx) {
    var options = allBindingsAccessor().ojSelectOptions || {};
    var multiple = !!options.multiple;
    var tabEl = $(element)
      // initialize ojSelect
      .ojSelect(options)
      // bind value change handler
      .on({
          'ojoptionchange': function (event, data) {
            if (data.option === "value") {
              var observable = valueAccessor();
              if (ko.isObservable(observable)) {
                if (multiple) {
                  observable(data.value);
                } else {
                  // unwrap from array if single select
                  observable(data.value[0]);
                }
              } // if not observable, just throw away the value
            }
          }
        })
      // get reference to item with tabIndex
      .ojSelect( "getNodeBySubId", {'subId': 'oj-select-chosen'})
      .closest(".oj-select-choice");

    $(tabEl).attr("tabIndex", -1);

  },
  update: function(element, valueAccessor) {
    var value = ko.utils.unwrapObservable(valueAccessor());
    $(element).ojSelect("option", "value", [value]);
  }
};

Note: The ojSelect value expects an array. In this JavaScript, notice that I distinguish between multi and single selection modes. For single-select ojSelect elements, I am unwrapping the value array and just returning the single value. This is for convenience and is in lieu of my other method for unwrapping ojSelect values.

You would use this with HTML similar to the following:

<select id="basicSelect" data-bind="inaccessibleOjSelect: browser,
                      ojSelectOptions: {optionChange: browserChangedHandler,
                           rootAttributes: {style:'max-width:20em'}}">
  <option value="IE">Internet Explorer
  <option value="FF">Firefox
  <option value="CH">Chrome
  <option value="OP">Opera
  <option value="SA">Safari
</select>

And finally, here is the jsFiddle so you can test it out:

As you review the code, you will notice that it is very ojSelect specific. As I mentioned before, not every Oracle JET input component requires a custom handler to change the tabIndex. For those that do, however, it wouldn't take much to rework this custom handler into something generic that could be used with a variety of ojComponent elements.

Wednesday, May 18, 2016

HTML5 Input Types for Oracle JET

I read an interesting question today, "Can you use HTML5 Input Types with Oracle JET's ojInputText?" Of course, the answer is "Yes" (the answer is always Yes). A better question is "How do you use HTML5 Input Types with Oracle JET's ojInputText?" OK, before we go there, let's answer the "Why" question: "Why would you use HTML5 Input Types with Oracle JET's ojInputText?" Oracle JET already includes number, text, and date input types, all styled according to the Oracle Alta specification. The reason for HTML5 Input Types? Device support. The idea behind HTML5 input types is to allow each device to display the most appropriate input method for a specific input type. This allows mobile web apps to maintain consistency with native mobile apps. For this reason, I am a HUGE fan of HTML5 input types. Note: desktop browsers don't have very good support for HTML5 Input Types.

Let's move onto the "How" question. Can you just set the type attribute of an ojInputText to "date" and get an HTML5 date input? No. Oracle JET will reset the type attribute to "text." The trick is to register a MutationObserver to listen for changes to the type attribute, and then reset it back to date (or whatever HTML5 input type you desire). Next question: How do I assign a MutationObserver to an instance of ojInputText? At this time, the best way I know to do this is with a knockout custom binding handler. You may remember that we used a custom binding handler last time we extended ojInputText (and then reused it a few more times). The reason for registering a ko.bindingHandler is to give us life cycle management events: we know when the DOM element is available and can enhance that element as we see fit. Here is an example of a custom component named html5DateInputText that extends ojInputText through ko.bindingHandlers. On initialization, the bindingHandler configures a MutationObserver that ensures the type attribute is always date. If you don't see a browser-specific date picker in the following example, then your browser might not support the date HTML5 input type. That doesn't mean the example is broken. It still works (depending on how you define the word "works") and falls back gracefully to a plain ojInputText.

Here is the custom binding handler:

var observerConfig = {
  attributes: true,
  childList: true,
  characterData: true
};
  
// Custom binding handler that wraps ojInputText and provides extra functionality
ko.bindingHandlers.html5DateInputText = {
    // setup extension to ojInputText as well as register event handlers
    init: function(element, valueAccessor, allBindingsAccessor, ctx) {
      var options = allBindingsAccessor().ojInputTextOptions || {};
      

      var observer = new MutationObserver(function(mutations) {
        ko.utils.arrayForEach(mutations, function(mutation) {
          if (mutation.type === 'attributes') {
            if (mutation.attributeName === 'type') {
              var $target = $(mutation.target);
              if ($target.attr('type') !== 'date') {
                $target.attr('type', 'date');
              }
            }
          }
        });   
      });
        
      observer.observe(element, observerConfig);
      
      $(element)
        .ojInputText(options)
        .on({
          'ojoptionchange': function (event, data) {
            //console.log(data)
            // use option === "value" for final value
            // use option === "rawValue" for each character
            if(data.option === "rawValue") {
              var val = data.value;
              var observable = valueAccessor();
              observable(val);
            }
          }
        })

      //handle disposal (if KO removes by the template binding)
      ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
        $(element).ojInputText("destroy");
        observer.disconnect();
        console.log("ojInputText destroyed");
      });
      
    },
    // This is how we update the UI based on observable changes
    update: function(element, valueAccessor) {
      var value = ko.utils.unwrapObservable(valueAccessor());
      $(element).ojInputText("option", "value", value);
    }
  };

If you want a different input type (tel, number, email and so on), then change lines 19 and 20 to match your target input type.

Note: The ojInputText Alta skin includes padding: 0 5px. The Chrome HTML5 Date spinners weren't centered using that padding so I added a line of CSS to reset padding to 5px on all sides.

Monday, May 9, 2016

rateLimit'ing ojInputText using a Read-only Observable (Debouncing the rawValue)

In my post Filtering Oracle JET ArrayTableDataSource I showed how to use an ojInputText to filter tabular data. In that post I mentioned using the knockout rateLimit extender, but shied away from it because rateLimit'ing an observable attached to an ojInputText rawValue throws the error, "rawValue option cannot be set" (even though rateLimit'ing in this manner works). It is true that rawValue is a read only field. For some reason, rateLimit'ing an observable causes a write to the component property bound to the observable. This makes sense because that is the point of an observable: update something after the observable value changes. The problem is that rawValue is read-only. I raised this issue with my colleagues and Jeanne Waldman shared this idea:

Create a pureComputed based off the rawValue observable and rateLimit the pureComputed.

Interesting. Jeanne's idea essentially creates a read-only observable that we can then rateLimit, effectively isolating rawValue from a write attempt. Here are the JavaScript changes necessary to implement Jeanne's idea:


// ... other code above here
ko.pureComputed(self.nameSearch)
  .extend({
    rateLimit: {
      timeout: 250,
      method: "notifyWhenChangesStop"
    }
  })
  .subscribe(function(newValue) {
    self.datasource.reset(
      filteredEmployees(newValue)
    );
  });

// ... other code below here

Notice that we are wrapping the previously used nameSearch observable in a ko.pureComputed, extending the ko.pureComputed, and then subscribing to the rate limited observable. Here is the jsFiddle:

Success! Our filter code now only runs 250 milliseconds after user input pauses. Considering our search algorithm, this will definitely perform better than invoking the algorithm for each key press. But is it as good as it could be? I'm not sure. We are now rate limiting a second observable rather than the primary observable. Will the primary observable continue to emit events with each key press? Did we trade an innocuous error message for some CPU/memory overhead? Does it matter? Normally, given two working solutions, I would choose performance, but I really don't want to see error messages cluttering my console.

Friday, May 6, 2016

Toast and Growl Notifications with Oracle JET

My colleague Paul Thaden just posted Creating a Popup Message Box for Oracle JET Forms which uses Oracle JET's Offcanvas functionality. While not exactly "toast," that was my first thought when I saw it. I really like the toast/growl notification concept and have been wondering how to add this type of notification to an Oracle JET project. Let's take Paul's work and convert it into a growl-like (or toast) notification complete with timeout. We will start with this modified version of Paul's jsFiddle. This fiddle displays a notification message when you change the selected browser.

Paul already explained the whole inner-wrapper/outer-wrapper thing so I won't repeat it here. Mainly I want to focus on styling the oj-offcanvas-top element (named toast) so that it floats on the right side of the page and then disappears after a specified period of time. Here is the only CSS we need:

#toast {
  /* Make the message look pretty */
  border: 1px solid #0572ce;
  box-shadow: 0 1px 3px #777;
 
  /* set the location of the toast message */
  left: auto;
  right: 10px;
  width: 200px;

  /* z-index required to overlay oj form controls */
  z-index: 1;
}

Next we refactor the ojSelect optionChange event handler from the prior jsFiddle to close the notification message after a specified interval:

var closeToast = function() {
  return oj.OffcanvasUtils.close(toastOptions);
};

self.browserChangedHandler = function (event, data) {
  if (data.option == "value") {
    oj.OffcanvasUtils.open(toastOptions);
    window.setTimeout(closeToast, 5*1000);
  }
};

Here is the jsFiddle example. Select a browser and watch the message appear and then disappear.

That is nice for a "Transaction saved" type of message, but let's get dramatic and make this look like a real growl notification. With a little bit of CSS, we can turn that Offcanvas notification into something like this:

And here is the jsFiddle:

Thursday, April 28, 2016

Animate Oracle JET Utility Classes (oj-selected)

Sometimes I build card-like user interfaces that allow users to select from a group of "cards." The visual state of a selected "card" should change once selected. The Oracle JET oj-panel, oj-margin, and oj-selected utility classes are great for this type of experience. The oj-panel and oj-margin classes setup the cards according to the Alta UI design patterns and oj-selected changes the appearance upon selection. Toggling oj-selected with a click binding is trivial with jQuery.toggleClass().

Out of the box, the oj-selected visual changes are either on or off. There are no transition states. I like user interface changes to morph between states. With just a couple of lines of CSS, we can animate what happens to an oj-panel when oj-selected is added to the panel:

.oj-panel {
  cursor: pointer;
  transition: border-color .3s ease-in-out;
}

Here is the jsFiddle

Is the fade effect too subtle for you? Take a look at this CodePen for some impressive animation examples.

Wednesday, April 27, 2016

Animated "Clear" button in ojInputText

Last week I posted Extending Oracle JET Components through Custom Bindings (Input Text with Buttons). About three quarters of the way through that post, I included a jsFiddle that shows how to add a delete button inside ojInputText. One of my readers asked if it was possible to hide the delete button if the ojInputText is empty. The answer, of course, is YES. The first thing we need to do is modify our ojoptionchange event handler to listen for the rawValue option instead of the value option. rawValue changes with each key press whereas value changes when the component loses focus.

.on({
  'ojoptionchange': function(event, data) {
    // use option === "value" for final value
    // use option === "rawValue" for each character
    if (data.option === "rawValue") {
      var observable = valueAccessor();
      //
      // ** show/hide icon code goes here
      //
      observable($(element).ojInputText("option", "value"));
    }
  }
})

If all we want to do is show/hide the "button" within the ojInputText, then we can toggle the oj-helper-hidden utility class on the i button element. That will result in the button instantly appearing or disappearing based on the length of the ojInputText element's value. I'm not a fan of jarring UX changes. If something is going to appear on the screen, I want it to fade in. The gradual appearance helps prepare my mind for the existence of a new user interface element while the movement draws my attention to this new element. Unfortunately, we can't animate the oj-helper-hidden class. The oj-helper-hidden class changes the display attribute and CSS does not support animating changes between the states of that attribute. We can, however, change the appearance of an element by animating the element's opacity. The following jsFiddle uses the opacity approach to toggle the appearance of the delete/clear button within ojInputText.

Extra credit: Compare these jsFiddles: http://jsfiddle.net/jmarion/tbr4k30n/ and http://jsfiddle.net/jmarion/5e10mx8z/. On line 62 of the first fiddle (my first post on this subject), I use jQuery to identify the value option of the ojInputText. In the second fiddle (this fiddle), lines 87 and 91 do the exact same thing, but without the jQuery method invocation. I got smarter the second time around. the ojOptionChange event actually includes the current value in the data object. I don't need to invoke a jQuery plugin method to retrieve the current value.

Note: I included CSS to change the cursor when the button becomes transparent, but the JavaScript click event will still trigger. Since the button is transparent when the ojInputText has no value, this should not be an issue. The net result of deleting nothing is... yep, you guessed it: nothing.

Oracle JET Utility Classes for Bootstrap Designers

I came to Oracle JET from a Bootstrap background. By looking through the examples and cookbook, it was easy to see Oracle JET's routing, data bound components, and layout features, but I missed Bootstrap's utility classes such as pull-right and text-right (Note: you can use Bootstrap and Alta together, but that is another story). I even began creating my own utility classes. Then, while reading a recipe in the cookbook, I stumbled across oj-helper-text-align-right. I thought to myself, "No kidding... Oracle JET has utility classes." In fact, the cookbook is littered with utility class references. For example, the Panel Selected recipe introduces oj-panel, oj-selected, and oj-margin. What is the significance of these classes? Just as Bootstrap helps developers adopt a common, modern look and feel based on the Bootstrap design guidelines, Oracle JET's utility classes ensure that we adhere to the Oracle Alta design patterns. We no longer have to ask, "How much margin should we place between infolets in a dashboard?" Instead, we can add the oj-margin class and know that we are adhering to the Oracle Alta design guidelines.

Oracle published a great Oracle JET CSS class reference so I won't repeat all of the utility classes here. But don't stop with that reference. Dig into the Sassy CSS (scss) where you will find even more gems such as oj-helper-hidden (a great class to mix with $(...).toggleClass). "Help! I looked I looked in the scss subfolder and there are TONS of files in there. Where do I start?" I suggest starting with _oj.common.utilities.scss and _oj.common.helpers.scss.

Helper classes such as .oj-helper-text-align-left and .oj-helper-text-align-right are great, but what about RTL? Here is where things get really cool: Oracle JET was designed for an international audience. Oracle JET alignment, padding, and margin classes include *-start and *-end complements that align, pad, and space elements properly for RTL languages.

Monday, April 25, 2016

jsFiddle for Oracle JET 2.0.1

Last month I put together an Oracle JET "base" jsFiddle using Oracle JET 2.0.0 (files served through the RawGit CDN). I naively believed I could just keep that base jsFiddle current and all forks would continue using older versions of Oracle JET. When Oracle JET 2.0.1 released, I tried to update that base jsFiddle and realized it was already current. Since RawGit pulls directly from GitHub (sort of; I'll explain later), no updates were necessary. My first thought was, "Wow, that is great!" My second thought was a bit terrifying, "What if a future Oracle JET release has different dependencies?" Every fiddle forked from that initial base fiddle would break. At that moment I realized I would have to version my Oracle JET base jsFiddle. Since the original was built on Oracle JET 2.0.0, I appropriately renamed it Oracle JET Base 2.0.0. If you review that jsFiddle, you will notice it now contains the release's commit hash, 49fcbbde7c8e178a3a21625d44485536e3ad1aaf, in URL's.

I just forked 2.0.0 into Oracle JET 2.0.1 and pointed the URLs at the 2.0.1 release commit. I recommend forking this new jsFiddle until the next Oracle JET release. Fortunately, the external dependencies (knockout, jQuery, etc) were the same between these 2.0.0 and 2.0.1, but don't count on that for future releases.

Why did I include source, unminified files in these jsFiddles? These jsFiddles are designed for testing, prototyping, debugging, and sharing. When asking for help in the Oracle JET OTN Forum, it is really helpful to use debug rather than minified files.

What about that RawGit CDN? RawGit serves raw GitHub content. While the content may be the same as appending ?raw=true, the delivery mechanism is different. URLs served from cdn.rawgit.com are actually served through MaxCDN's network. Files are permanently cached so requests don't actually travel back to a git repo. Because of the longevity of the word permanent, the RawGit FAQ encourages the use of commit hashes to ensure serving the correct version. This is why I said earlier that "RawGit pulls directly from GitHub... sort of," and another good reason to reference the commit hash in URLs.

Tuesday, April 19, 2016

Extending Oracle JET Components through Custom Bindings (Input Text with Buttons)

The other day I saw an interesting question on an Oracle JET forum: "Can you add a clear button inside the end of an ojInputText?" Think of this like the magnifying glass at the end of a search field or an X that allows you to delete all of the text within an ojInputText. My first thought was to use a little CSS to add a FontAwesome icon to the end of the data entry field. If we were using a plain HTML input element, this would be no small task because it is impossible to use CSS alone to add an icon to the end of an input element (maybe someday HTML and CSS will support before and after selectors for input elements?). ojInputText, however, already wraps input elements in an outer div so we just need to add a little CSS to style that outer div. Here is an example that just uses CSS styling

You see a problem with this solution? I didn't at first. From a visual perspective, it meets all of the requirements—oh, except it isn't a button. If all you want is a visual indicator/icon within ojInputText, then this is a small, tidy solution will suffice. If you actually wanted a button, then keep reading.

My colleague Paul Thaden reworked my example for click events:

Notice this example replaces the :after pseudo selector with jQuery append. This allows us to handle the icon's click events. This is a great, simple solution if you need to handle click events AND know when elements will exist in the DOM (so you can wire up event handlers, enhance the markup, etc). But what about those times when elements are created and destroyed through iterators or View/Component changes? What we really need is a way to manage the component's lifecycle so we can enhance and wire up event handlers on creation. Knockout has a mechanism for this called Custom Binding Handlers.

Have you noticed the $(".selector").ojFoo syntax in a lot of the Oracle JET JSDocs? That looks a lot like the jQuery UI syntax (because it is—thank you JB for confirming, see this video). If Oracle JET components are a lot like jQuery UI widgets, then we are in luck. The internet is littered with examples of people creating custom binding handlers for jQuery UI components. Here is a great example that creates a custom binding handler for the jQuery UI datepicker. All we need to do is follow that example, replacing datepicker with ojInputText. In other words, we can extend any Oracle JET component binding by pretending it doesn't have bindings and treating it like a jQuery plugin. Here is a jsFiddle showing examples of two-way data binding and data model creation/destruction, etc:

Too much clutter? Just want to see the ojInputText extension? Here is the HTML

<input id="text-input" 
       type="text"
       data-bind="audioInputText: value,
                  ojInputTextOptions: {rootAttributes:
                                        {class: 'audio-ojInputText'}}"/>

And the JavaScript

ko.bindingHandlers.audioInputText = {
    // setup extension to ojInputText as well as register event handlers
    init: function(element, valueAccessor, allBindingsAccessor, ctx) {
      var options = allBindingsAccessor().ojInputTextOptions || {};
        
      $(element)
        .ojInputText(options)
        .on({
          'ojoptionchange': function (event, data) {
            // use option === "value" for final value
            // use option === "rawValue" for each character
            if(data.option === "value") {
              var observable = valueAccessor();
              observable($(element).ojInputText("option", "value"));
            }
          }
        })
        .closest(".audio-ojInputText")
          .append('')
          .find("i")
            .click(function() {
              var msg = "This could activate the microphone... but it doesn't. " +
                "Hey, I noticed you entered '" +
                ko.utils.unwrapObservable(valueAccessor()) + "'"
              alert(msg);
            });

      //handle disposal (if KO removes by the template binding)
      ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
        $(element).ojInputText("destroy");
        console.log("ojInputText destroyed");
      });
        
    },
    // This is how we update the UI based on observable changes
    update: function(element, valueAccessor) {
      var value = ko.utils.unwrapObservable(valueAccessor());
      $(element).ojInputText("option", "value", value);
    }
  };

Here is an example of an ojInputText with a delete button that deletes all of the text within the observable when clicked.

In each of the examples above, I hard coded the click handler and the icon. In prior examples, the click handler used model data, making it somewhat generic, but not generic enough to delegate clicks to the ViewModel. Let's create one final example that we'll call ojInputText Clear Buttons. This example is generic enough to use any icon library (glyphicons, fontawesome, oj icons, etc) and invokes a click handler within the ViewModel.

Thursday, April 14, 2016

Fade-in Animation for Oracle JET ojDialog

It may just be my eye-mind coordination (or lack thereof), but I have trouble adjusting to abrupt user interface changes. For example, if I click a button and a dialog box instantly appears, my business-related thought processes pause for a moment while I try to mentally digest what just happened and why. It is mentally easier for me if user interface changes occur through fast, but gradual animations. Don't waste my time with a slow animation... but then again, don't waste my time with no animation. I function best when enterprise application developers use animations to prepare my mind for the next step. So here I am developing an enterprise application with Oracle JET and using ojDialog. As my ojDialog appears, I think to myself, "Where is the animation?"

Here is how I added fade-in animation to ojDialog. Starting from the ojDialog cookbook recipe, I added the class animate as a rootAttribute to identify that this dialog should be animated:

<div id="dialogWrapper">
  <div style="display:none" id="modalDialog1" title="Modal Dialog" 
       data-bind="ojComponent:{component: 'ojDialog',
                               initialVisibility: 'hide',
                               rootAttributes: {
                                 class: 'animate'
                               }}">
     <div class="oj-dialog-body">
       The dialog window can be moved, resized and closed with the 'x' icon.
       Arbitrary content can be added to the the oj-dialog-body and
       oj-dialog-footer sections.
     </div>
     <div class="oj-dialog-footer">
        <button id="okButton" data-bind="click: closeDialog,
                                         ojComponent: {component: 'ojButton',
                                                       label: 'OK'}"> 
      </div>
  </div>
  <button id="buttonOpener" data-bind="click: openDialog,  
                                       ojComponent: {component: 'ojButton',
                                                     label: 'Open Modal Dialog'}">

</div>

Next I added some CSS to set the initial opacity for all animated ojDialogs to 0, meaning fully transparent:

.oj-dialog.animate {
  opacity: 0;
  transition: opacity .25s ease-in-out;
}

Now when I invoke the open method, the dialog will appear, but it will be fully transparent which means I won't actually be able to see it (talk about usability and user interface design!). Then I added a new selector and corresponding CSS to represent a dialog in the fully opaque state:

.oj-dialog.animate.fully-opaque {
  opacity: 1;
}

The plan is to toggle the fully-opaque class on the oj-dialog.animate selector when the dialog opens. Let's revisit that dialog HTML definition and add an open event handler:

<div style="display:none" id="modalDialog1" title="Modal Dialog" 
     data-bind="ojComponent:{component: 'ojDialog',
                             initialVisibility: 'hide',
                             open: dialogOpen,
                             rootAttributes: {
                               class: 'animate'
                             }}">

And now the JavaScript to handle the open event:

    self.dialogOpen = function(event, ui) {
      $(event.target)
        .closest(".oj-dialog.animate")
        .addClass("fully-opaque");
    };

Since we added a CSS transform to oj-dialog.animate the ojDialog container will fade in from 0 to 100% opacity. Notice the interesting selector in that JavaScript fragment? The event target is the ojDialog div we defined, but Oracle JET wraps that element in a new root element. It is THAT element we want to animate (hence the use of rootAttributes in the ojDialog definition). There are probably a million different selectors I could have chosen. In fact, $(event.target).parent() was my first idea, but then I thought, "what if the ojDialog structure changes?"

If you followed these steps, you should now have an ojDialog with a fade-in effect. What about fade-out? I don't have a good answer here. I tried both the close and beforeClose events, but those happen too quickly, meaning the dialog display is changed to hidden before the animation. My not-so-good work-around is to perform the animation when the user clicks the OK button in the dialog footer:

self.closeDialog = function(data, event) {

  // attempt fadeOut with jQuery
  $(event.target)
    .closest(".oj-dialog.animate")
    .fadeOut(function() {
      $("#modalDialog1").ojDialog("close");
    });
  };

I put together a jsFiddle named ojDialog Fade-in to demonstrate the animated ojDialog. Once Oracle JET starts accepting pull requests, perhaps animations would be a valuable community enhancement?

Wednesday, April 13, 2016

Help! I'm using Asynchronous JavaScript and my View isn't Updating

One of the most common knockout binding questions/misunderstandings I see involves updating Knockout Observables with Asynchronous data. Whether it is a select/options list, a table, a chart, or any other data-driven component, we often load data asynchronously (Ajax). The benefit of this asynchronous architecture is that our View renders before the ViewModel has all of its data. Users see most of the application render and have a feeling of better performance. It is at this render point that bindings are bound—data pointers are locked in. Now the data arrives... how you push those data values into the bound observables can be the difference between success and failure. In this blog post I want to share with you a few ways to update observables while ensuring the View stays bound to the ViewModel. First things first: we need a mock Ajax service that returns data asynchronously. In this case, mock means we aren't actually going to fetch data via Ajax. We are just going to yield JavaScript execution for a short period of time. The following listing uses setTimeout to mimic the delay of an asynchronous response:

var fakeJAX = function() {
  return new Promise(function(resolve, reject) {
    window.setTimeout(function() {
      resolve([
        {id: 101, name: "Beauregard Duke"},
        {id: 102, name: "Lucas Duke"},
        {id: 103, name: "Daisy Duke"},
        {id: 201, name: "Cooter Davenport"},
        {id: 301, name: "Jefferson Davis Hogg"},
        {id: 302, name: "Lulu Coltrane Hogg"},
        {id: 401, name: "Rosco P Coltrane"}
      ]);
    }, 2000);
  });
};

As you can see, the method returns an HTML5 Promise that resolves when the timer expires (2 seconds). The result/interface is designed to mimic the fetch API.

When it comes to out-right errors, here is the common one I see:

var ViewModel = function() {
  var self = this;

  self.employees = ko.observableArray([]);

  self.datasource = new oj.ArrayTableDataSource(
    self.employees, {
      idAttribute: 'id'
    });
      
  // Array Push All option
  fakeJAX()
    .then(function(data) {
        self.employees = ko.observableArray(data);
      });
  };

Do you see the problem? Inside the Asynchronous response handler, we are changing the self.employees pointer. This breaks the relationship between our ViewModel and the DOM. The view now points to the old memory space whereas self.employees points to a new memory space. Note: Later you will see how to work around this by using the if binding.

Now let's look at an example that is technically correct, but may not work with certain components because of the internal workings of the component (the way the component is implemented and how it binds to the observable). In Knockout it is common to swap out the value of the observable. This works great... most of the time. Here is an example:

fakeJAX()
  .then(function(data) {
    self.employees(data);
  });

Now don't get me wrong. This works most of the time. But if you find that your observable isn't updating, then try pushing values directly into the array wrapped by the Observable Array. Here is an example:

fakeJAX()
  .then(function(data) {
    ko.utils.arrayPushAll(self.employees(), data);
    self.employees.valueHasMutated();
  });

There are times where pushing into the array in-place won't work either. If you find yourself in a situation where the last two options won't work, then try this next approach. I have yet to find a scenario where this next approach does not work. It uses the knockout if binding to hide a data bound element from the DOM until we have data. Here is an HTML example of a table wrapped in an if binding:

<!-- ko if: haveEmployees --> 
  <table id="table" summary="Employee Table 2" aria-label="Employee Table"
         data-bind="ojComponent: {component: 'ojTable',
                    data: datasource,
                    columnsDefault: {sortable: 'none'},
                    columns: [{headerText: 'Employee Id',
                    field: 'id'},
                    {headerText: 'Employee Name',
                    field: 'name'}]}">
  </table>
<!-- /ko -->  

Notice the haveEmployees ViewModel observable? There are a couple of ways to implement that observable, but my favorite way is through a knockout pureComputed like this:

self.haveEmployees = ko.pureComputed(function() {
  return (self.employees().length > 0);
});

Now when the fakeJAX success handler populates the observableArray, the hasEmployees pureComputed will automatically flip from false to true and the table will suddenly appear in the DOM. It is at this moment that knockout will bind observables to attributes. Since binding happens after we have data, this may seem like the easiest approach. In my opinion, however, this should be the last option chosen because it hides a portion of the user interface until the Ajax response.

I put together a jsFiddle showing the last two approaches named Async Data Binding.

Interested in learning more? Here are a couple of Oracle JET OTN Discussion Forum threads discussing this very topic:

Special thank you to @JB, Oracle JET product manager for chiming in on those threads

Thursday, March 24, 2016

Using FontAwesome and Glyphicons with Oracle JET

Oracle JET includes an excellent list of common icons in the Framework Images Recipe. To use one, add the oj-fwk-icon and icon specific class to any element (<i> is a common element). For example:

<i class="oj-fwk-icon oj-fwk-icon-magnifier"></i>

The Oracle JET Cookbook contains great examples of using the oj-fwk-icons with common Oracle JET components. Sometimes, however, I find I need more icons. Two of my favorite icon libraries are FontAwesome and Glyphicons (the Bootstrap ones). To use either of these libraries, first include the library's CSS. Second, replace the oj-fwk-icon and oj-fwk-icon-* classes with the appropriate library specifc class. For example, to use the FontAwesome magnifier, use fa fa-search. I put together a very short jsFiddle showing how to use FontAwesome with some of the more common Oracle JET elements such as ojButton and ojMenu:

Filtering Oracle JET ArrayTableDataSource

I recently wrote about Filtering Table Data with Knockout Computeds. I'm not sure I shared anything earth shattering as others have already written about that topic. My real motivation for writing that post was to provide a foundation to compare/contrast filtering a plain HTML table against an Oracle JET ojTable that is based on an oj.ArrayTableDataSource (not to be confused with oj.CollectionTableDataSource, which wraps an oj.Collection and has its own where method and cookbook example).

Let's jettify the Filtering Table Data with Knockout Computeds example. Instead of <input type="text">, we'll use ojInputText. Instead of a Bootstrap table, we'll use ojTable. Here is the jsFiddle:

As you can see, the code is fairly similar. A couple of key differences to note are the rawValue parameter and the lack of a computed. Instead of using the value and valueUpdate parameters, the ojInputText component uses value and rawValue. The ojInputText value parameter acts just like the standard knockout parameter, tracking the final updated value after losing focus. The rawValue parameter tracks changes as you type, which is similar to the standard input with the valueUpdate parameter. The other difference between these examples is that this example didn't use a computed observable, but rather the oj.ArrayTableDataSource.reset() method to replace the table's array when filtering.

As with the Knockout computed example, we can debounce this example so that the array filter code doesn't run with every key press, but only after a predetermined pause. I included the rate limiting extension in the JavaScript, but commented it out for example purposes. When filtering large data sets, it might make sense to switch from observing rawValue to observing the value parameter. Another option is to include a Search button that triggers the filter code on click. You can find an example of this here.

Note: Filtering arrays requires an ES6 compatible browser or some type of polyfill library. The examples include Lazy.js as a polyfill so you can run the jsFiddle example in a wider range of web browsers.

Wednesday, March 23, 2016

Filtering Table Data with Knockout Computeds

Before learning to love Knockout, I was an AngularJS fan. AngularJS has this really cool feature called filters that let you pipe a collection through a filter, filtering results based on the value of a field. The AngularJS filter page has a great inline example. You can filter with Knockout, but it isn't quite as simple. The key to filtering in Knockout is the computed observable. I put together an example:

This example contains a search field in the upper right corner as well as a table of employee names. If the filter field is empty, then the table should display all employees. If the filter field contains a value, then the table should display only employees with names containing the search value. When you look at the JavaScript for this example, you will see:

  1. An array of employees (the raw, unobserved data),
  2. An observable for the search value, and
  3. A computed for the filtered table

Drilling into the computed observable (filteredEmployees), we see that the function immediately returns the list of all employees if the nameSearch observable has no value. If it has a value, then it returns a filtered array of matching results.

I put together 2 examples: One with ES6 Array and String extensions and a Lazy.js version. The example above is the Lazy.js version. ES6 is great, but jsPerf tests show better results for ko.utils, underscore, Lazy.js, or just about any other non-native library. I also hesitate to use the ES6 Array.prototype.filter for browser compatibility reasons. Just in case you are interested, Here is the ES6 version. Why Lazy.js instead of just ko.utils.arrayFilter? I am a big fan of Lazy.js's function composition rather than the traditional chained intermediate array concept (even though this example doesn't exactly chain enough array methods together to see a performance improvement from Lazy.js).

On the HTML View side, the search field's data-bind attribute uses the valueUpdate parameter. This causes Knockout to update the ViewModel on some other event besides the change event. That way users can see changes as they type. What this means is as you type, the filter code will run, filtering the results displayed in the table. We have a small data set, so you won't notice, but on a larger data set, this could have serious performance implications because each key press would iterate over the Employees array. We can limit how often knockout recomputes the computed observable by debouncing, or rate limiting, updates of nameSearch field like this:

self.nameSearch.extend({
    rateLimit: {
      timeout: 500,
      method: "notifyWhenChangesStop"
    }
  });

You can see an example here. Notice that the update is a little choppier, meaning the table filters a half second after you stop typing. A half second may be a little too long between updates. The important part is that the code recalculates the computed AFTER the specified event pauses for a predetermined interval.

Fiddling Around with Oracle JET

I learn new ideas, technologies, etc by example. First I am presented with a challenge (a new project, new idea, etc) and then I search for ways others have built similar solutions. While looking through search results, I almost always pause when I see a stackoverflow response. I think I learn more from stackoverflow than I do from any other source on the Internet. Often times while reading a stackoverflow answer, I'll find myself in a jsFiddle, manipulating someone else's example in an attempt to understand the solution. Wouldn't it be great to find Oracle JET fiddles demonstrating ideas that are not in the JET cookbook?

A key to building a jsFiddle that references a library is accessibility to that library. Many of Oracle JET's dependencies are hosted on Content Delivery Networks (CDNs), making them accessible to jsFiddle. At this time, Oracle JET itself is not available on a CDN. Oracle JET is, however, accessible via GitHub. This is good news because there is a site named RawGit that serves GitHub project files through MaxCDN. If you want to access the Oracle JET Alta skin for example, enter https://github.com/oracle/oraclejet/blob/master/dist/css/alta/oj-alta-min.css into the file name field and RawGit will give you a URL such as https://cdn.rawgit.com/oracle/oraclejet/master/dist/css/alta/oj-alta-min.css.

I went through the Oracle JET 2.0 bower file and created a RequireJS configuration based on JET's dependencies. This is step #1 in creating a jsFiddle. Here is what that CDN version looks like (note: I used the RawGit dev URL, not the production URL, for jsFiddle):

requirejs.config({
  // Path mappings for the logical module names
  paths: {
    'knockout': '//cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min',
    'jquery': '//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min',
    "jqueryui": "//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui",
    "jqueryui-amd": "//rawgit.com/jquery/jquery-ui/1-11-stable/ui",

    "promise": "//cdn.lukej.me/es6-promise/1.0.0/promise.min",
    "hammerjs": "//cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.4/hammer.min",
    "ojdnd": "//rawgit.com/oracle/oraclejet/master/dist/js/libs/dnd-polyfill/" +
        "dnd-polyfill-1.0.0.min",
    "ojs": "//rawgit.com/oracle/oraclejet/master/dist/js/libs/oj/debug",
    "ojL10n": "//rawgit.com/oracle/oraclejet/master/dist/js/libs/oj/ojL10n",
    "ojtranslations": "//rawgit.com/oracle/oraclejet/master/dist/js/libs/oj/" +
        "resources",
    "text": "//cdnjs.cloudflare.com/ajax/libs/require-text/2.0.12/text.min",
    "signals": "//cdnjs.cloudflare.com/ajax/libs/js-signals/1.0.0/js-signals.min",

  },
  // Shim configurations for modules that do not expose AMD
  shim: {
    'jqueryui-amd': {
      exports: "$",
      deps: ['jquery']
    },
    'jquery': {. The 
      exports: ['jQuery', '$']
    }
  },
  config: {
    ojL10n: {
      merge: {
        //'ojtranslations/nls/ojtranslations': 'resources/nls/menu'
        // The following addes en-US to the r.js bundle
        //'ojtranslations/nls/ojtranslations': '../../oj/resources/nls/en-US/localeElements'
      }
    }
  }
});

I combined all of this into a new jsFiddle.

I didn't think it was very exciting to just put the RequireJS config and Alta CSS into the fiddle without any content. I wanted a simple example that showed how RequireJS resolved dependencies using the relative ojs paths so I borrowed from the Input Date and Time cookbook entry.

Please fiddle and fork to your heart's content!

NOTE: The jsFiddle is a living example, meaning I make changes to the base fiddle on occasion to keep it current. The code displayed in this post, however, won't change. For example, the jsFiddle currently uses cdn.rawgit where as the code in this post uses the development rawgit server. When in doubt, trust the fiddle.

Update 25-Apr-2016: Oracle JET 2.0.1 was just released. Without any changes, the original jsFiddle nicely began using 2.0.1. As I was considering releases, it occurred to me that a future release of JET may require different dependencies. The JET libraries would be always current, but the dependencies (knockout, hammer, jQuery, etc) may be become irrelevant. With that in mind, I updated the fiddle for this post to point specifically to the 2.0.0 commit from February 29, 2016. I will add another jsFiddle for 2.0.1 and announce it as a blog post.