In previous blog entries we have already written about our experiences in developing JavaScript add-ins for Microsoft Dynamics NAV 2013 R2 and 2015 which are capable of being used in the Web Client of NAV as well as in the Windows Client.
With NAV 2015, Microsoft introduced a new app internally called the Tablet Client, which is available for several platforms, namely Microsoft Windows 8.1, Google Android and Apple iOS. This Tablet Client basically is a web browser container hosting NAV pages. The pages can host embedded control add-ins that are written using HTML and JavaScript, just like the Web Client of NAV. The platforms named above require the user interface content to be prepared for touch gestures.
Two issues are crucial in this context:
Here are the basic touch gestures usually expected of a tablet application :
It is also possible to combine touch gestures by using more than one finger or by requiring two gestures in sequence such as ‘Press’ and ‘Pan’.
The possible mouse gestures should be known to most people by now so that we refrain from explaining them here: left/first button click, right/second button click, left button double click, drag, hover, wheel action.
All web browsers simulate mouse events for taps and for swipes. When it comes to distinguishing mouse from touch gestures in a web application, simulated mouse events are not welcome so that we have to try to switch them off. This requires browser-dependent steps since the World Wide Web Consortium (W3C) has not standardized touch behavior to the end. Unfortunately, the appropriate CSS attribute ‘touch-action’ is not supported by Safari in iOS 8.1 at the moment. In addition, there are two sets of touch events: Internet Explorer implements unified pointer events for mouse and touch input, whereas Chrome and Safari implement pure touch events. Firefox implements both sets, but has disabled touch support since version 25.
We began searching for a JavaScript library which could help in terms of distinguishing between mouse and touch events and could handle the browser-dependent differences itself so that we could focus on implementing the actions for the gestures. The JavaScript community is very large and produces many plug-ins and libraries so that we were sure to find something (e.g. see http://www.queness.com/post/11755/11-multi-touch-and-touch-events-javascript-libraries).
Since the web browsers' support changes with every version of each browser and the W3C standardization keeps evoling, a library needs to be maintained, if necessary, quickly after the release of new browser versions of Internet Explorer, Chrome, Firefox, and Safari. Moreover, the library should handle all known touch gestures because the browsers themselves only trigger simple touch start, move, end events and hence do not trigger individual events for multi-touch gestures such as pinching and rotating.
We were surprised that only one JavaScript library really met all our criteria: Hammer.js (see http://hammerjs.github.io/) is a library that:
So we began implementing our interactions using Hammer.js which can be done in a very direct and easy way, as can be seen in the following small code example:
// define the DOM element, which should get Hammer events
var myElement = document.getElementById('myElement');
// create a Hammer.Manager object
var mc = new Hammer.Manager(myElement);
// create Hammer.Recognizer objects for touch gestures…
var doubleTap = new Hammer.Tap({ event: 'doubletap', taps: 2 });
var press = new Hammer.Press();
// … and add them to the Manager
mc.add([doubleTap, press]);
// attach event listeners
mc.on('doubletap', function (ev) { /*...*/ });
mc.on('press', function (ev) { /*...*/ });
});
Initially, we did not recognize that our application was getting slower and slower, especially in Internet Explorer while implementation of touch event actions grew and grew. Inside the NAV Windows Client, the Internet Explorer actually is used in the form of a browser control to show the JavaScript control add-ins, so IE was essential for our control add-in: Loading a bigger amount of data took 5 minutes instead of 10 seconds before using Hammer.js. This came as a great shock!
After doing some profiling, we found the culprit: The Internet Explorer has a performance weakness in terms of adding event listeners. Since we added Hammer.Recognizer objects for every table cell and for every operation in the chart and each Hammer.Recognizer itself adds several mouse and touch event listeners to the assigned DOM element a different solution had to be looked for.
We found it in using a refined approach: We now create only a single Hammer.Manager object and assign it to the SVG root element. Then one appropriate Hammer.Recognizer object was added for each gesture type needed in the application. That's why we only have a constant number of event listeners regardless of the number of table rows and operations.
Each DOM element that should really process Hammer events has to get two things:
Finally we implemented a new object called EventDispatcher, which listens to all events triggered from the single Hammer.Manager object by searching for the actually targeted DOM element and triggers the custom event to it, while the ‘detail’ attribute of the custom event object holds the original Hammer event object.
In addition, the refined approach now enables us to implement supplemental behaviors at a central point:Within our control add-in we also distinguish between mouse and touch events in cases that require a different behavior:
Although it seems to be a brave new world where the handling of touch events is concerned, weird issues came up when using different web browsers. We found out that it is always a bad idea to implement conditional code and styles dependent on browser, platform or device characteristics. Often it is better to find a constellation of HTML, JavaScript, and CSS that works for all devices. This may take time, but it is worth it.
In order to debug problems that only occur within the Tablet Client of NAV you will have to use the ‘tablet.aspx’ web page for NAV developers instead, because you cannot debug published apps on the iPad for instance. Caution: A web application running inside Safari on the iPad can only be debugged when the iPad’s USB cable is plugged into a Mac.
For the Web Client of NAV we also had to debug on a Windows machine with a touch monitor and several web browsers. We found out that Firefox has given up on supporting touch events for the time being, whereas the Internet Explorer 11 does not provide the right number of fingers that the monitor is able to recognize at once (navigator.maxTouchPoints), while Chrome does it right! So it is critical to detect the availability of a touch device on the Windows platform (see http://stackoverflow.com/questions/4817029/whats-the-best-way-to-detect-a-touch-screen-device-using-javascript). Windows is also the only operating system providing mouse and touch functionality simultaneously. The user can use both input devices, this being tricky for an application by means of implementing intuitive interactions for both types of input.
Handling touch events is not as easy as is proclaimed on some web sites since we develop a full-blown application that in theory should run platform-independent. Each touch gesture has to be handled being aware of conflicts with other gestures and/or other visual elements in the neighborhood. The web browsers trigger touch events differently and simulate mouse events, which can have negative side effects.There's no guarantee that a behavior's functioning remains the same after a web browser update. We found out that it is helpful to use a JavaScript library like Hammer.js in order to abstract from browser capabilities. After all, our control add-in gained intuitive touch interactions in addition to the usual mouse interactions. You can see the success of our efforts when using the current version 1.1 of VPS Web Client for Microsoft Dynamics NAV. We will go on in providing the best possible user experience for our customers.
Are you interested in learning more about the Visual Production Scheduler Web Client? Request your demo now!