Wednesday, March 28, 2012

Developing metro apps (HTML & JS): My point of view

Last Friday I attended the first windows 8 developer day in Belgium. A great opportunity to learn a bit more about developing Metro apps. One of the demos given by Giorgio Sardo showed how easy a HTML 5 application could be copied and pasted into a Metro app without having to rework even a single line of code. At first sight this looks pretty amazing, but I got me thinking.
The first thing I noticed is the fact that the HTML 5 application was actually a game. That is one of the reasons it could be easily ported to a Metro app. If we would want to port a business app like an e-commerce site, that wouldn’t be so easy. One of the important issues when developing Metro apps is the design. The philosophy of Microsoft when designing an application is that all applications have a similar look & feel and should react on the same way.
Almost all websites are designed for a single resolution and that is in contrast with the Metro philosophy where all apps should optimize their viewport for every screen. This means you’ll have to redesign your application so it changes its content to fit to the screen. Also you should implement the capabilities to change the view depending on the position of your device (landscape or portrait mode) and the multitask options which allows you to run multiple applications side by side.
Next to the Metro design these Metro apps should at least have some specific windows 8 features like redefined search and sharing capabilities. It's only at this point you really start to take advantage of some of the new windows 8 features. But the most important thing you should implement is the live tile. This must engage the user to consume your application. You can do this by providing the user real-time information about your app.
A second consideration is the fact when you just copy and paste your web application, you don’t take advantage of all the possibilities present in WinRT. With WinRT you can make calls to the operating system. For example you can access the webcam, save a file to the file system; share data … Developing Metro apps with JavaScript also brings the WinJS namespace. In here we find the Promise object that enables an easy way for the developer to handle asynchronous calls. Because all calls that take more than 50ms are preformed asynchronous by default, this can come in handy when you are making WinRT calls.
After the theoretical part, it was time for the real work: an App-a-thon. Here we got the possibility to put all our theoretical knowledge into practice. Together with 4 RealDolmen colleagues (Maarten Balliauw, Xavier Decoster, Wesley Cabus and Angelo Trotta) we developed a metro Nuget Package Explorer. This allows the users to view NuGet repositories and their package details. All this information gets retrieved from the given feeds and gets stored in an IndexedDB for performance. The application is completely build in HTML5 and uses JavaScript for the logic.
Surprisingly, developing this application went pretty fast. I took some time to adjust to the fact your writing a client application with JavaScript, but all knowledge about JavaScript in the past, could be reused pretty easy. There was one thing we were struggling with. When working with the promises you have to be very careful to call objects in the UI-thread, otherwise you can get some strange exceptions.
Conclusion
After a whole day Windows 8, I really excited to start develop metro apps. Enabling developers to develop a metro app in HTML/JS was definitely a good choice Microsoft made. This way a whole new group of developers can start building Metro apps. But the business has to be aware that you can’t just copy and paste your web app in a Metro project and call it Metro app. Metro apps have a philosophy and that should be respected. Also it would be a shame if you wouldn’t take advantage of all the new features that Metro apps provide.
I’m looking forward to the next app-a-thon and hope that our team can come together again to win the contest this time. (Ended second last time.)
Currently I’m trying to port our Linq2IndexedDB project to use the WinJS promises instead of the jQuery promise. I hope to announce this feature in the near future.

Saturday, March 10, 2012

JavaScript: Change entered character in keypress event

Recently I came across a problem with a numeric input field. For globalization issues a decimal had to be separated by a comma instead of a dot. So there were 2 solutions in this case. I could prevent users from typing in the dot, or I could replace the dot by a comma when typed. I went for the second one, because on the numeric keypad you only have a dot. So this way it would be easier for the users to input the decimal. It also works the same as applications like Excel who change the dot to a comma to if your regional settings are set that way.

At first sight this looked like an easy chore. In most cases the keypress or keydown event gets handled and the keyCode of the dot gets blocked. Instead the comma is added at the end of the current value of the input field.

   1: // All decimal input fields have a class named 'number'
   2: $('input.number').each(function (){
   3:     $(this).keypress(function(e){
   4:         // '46' is the keyCode for '.'
   5:         if(e.keyCode == '46' || e.charCode == '46'){ 
   6:             //Cancel the keypress
   7:             e.preventDefault(); 
   8:             // Add the comma to the value of the input field
   9:             $(this).val($this.val() + ',');
  10:         }
  11:     });
  12: });
  13:  

In most cases this will do, but when users start editing the decimal, troubles arrive. When the user types a dot inside the number, the comma will be added at the end of the number. But this isn’t what the user wants. He wants to have the comma placed on the location where he type the dot. After some googling, I found the following solution:



   1: // All decimal input fields have a class named 'number'
   2: $('input.number').each(function () {
   3:     $(this).keypress(function(e){
   4:         // '46' is the keyCode for '.'
   5:         if(e.keyCode == '46' || e.charCode == '46'){
   6:           // IE
   7:           if(document.selection){
   8:                 // Determines the selected text. If no text selected,
   9:                 // the location of the cursor in the text is returned
  10:                 var range = document.selection.createRange();
  11:                 // Place the comma on the location of the selection,
  12:                 // and remove the data in the selection
  13:                 range.text = ',';
  14:           // Chrome + FF
  15:           }else if(this.selectionStart || this.selectionStart == '0'){
  16:                 // Determines the start and end of the selection.
  17:                 // If no text selected, they are the same and
  18:                 // the location of the cursor in the text is returned
  19:                 // Don't make it a jQuery obj, because selectionStart 
  20:                 // and selectionEnd isn't known.
  21:                 var start = this.selectionStart;
  22:                 var end = this.selectionEnd;
  23:                 // Place the comma on the location of the selection,
  24:                 // and remove the data in the selection
  25:                 $(this).val($(this).val().substring(0, start) + ','
  26:                  + $(this).val().substring(end, $(this).val().length));
  27:                 // Set the cursor back at the correct location in 
  28:                 // the text
  29:                 this.selectionStart = start + 1;
  30:                 this.selectionEnd = start +1;
  31:             }else{
  32:                 // if no selection could be determined, 
  33:                 // place the comma at the end.
  34:                 $(this).val($(this).val() + ',');             
  35:             }
  36:             return false;
  37:         }
  38:     });
  39: });



What we do is use the provided functionalities in the browsers for detecting selections in an input field. If no text is selected, the range will return the location of the cursor inside the input field. This way we can provide the correct implementation. So even when text is selected and the dot key is pressed, the selected text will be replaced by the comma.