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