Thursday, July 30, 2015

Magic $parse service in AngularJS

AngularJS has a useful, but less documented $parse service which is shortly described in the Angular's docu as "converts Angular expression into a function". In this post, I will explain what this description means and show explicit and implicit usages of $parse. Furthermore, we will see the differences to the Angular's $interpolate service and $eval method.

Implicitly used $parse

The $parse compiles an expression to a function which can be then invoked with a context and locals in order to retrieve the expression's value. We can imagine this function as a pre-compiled expression. The first parameter is context - this is an object any expressions embedded in the strings are evaluated against (typically a scope object). The second parameter is locals - this is an JavaScript object with local variables, useful for overriding values in context. I've created a simple plunker to demonstrate the simple usage.
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  </head>
  <body ng-app="app">
    <h1>Magical $parse service</h1>
    
    <div ng-controller="ParseController as vm">{{vm.parsedMsg}}</div>
    
    <script src="https://code.angularjs.org/1.4.3/angular.js"></script>
    <script src="app.js"></script>
  </body>
</html>
In the HTML we output the controller's variable parsedMsg which is created in the app.js as follows:
(function() {
  angular.module('app', []).controller('ParseController', ParseController);

  function ParseController($scope, $parse) {
    this.libs = {};
    this.libs.angular = {
      version: '1.4.3'
    };

    var template = $parse("'This example uses AngularJS ' + libs.angular.version");
    this.parsedMsg = template(this);
  }
})();
As you can see, the expression 'This example uses AngularJS ' + libs.angular.version gets parsed and assigned to the variable template. The template is a function which is invoked with this object as context. The this object containes the value of libs.angular.version (nested objects). This value is used when evaluating the pre-compiled expression. The result is saved in this.parsedMsg and shown in the HTML.

It is important to understand that $parse can be invoked once and its result (pre-compiled expression) can be used multiple times with different context (and locals). The next plunker demonstrates the usage of just one pre-compiled expression with different locales. The HTML part:
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  </head>
  <body ng-app="app">
    <h1>Magical $parse service</h1>
    
    <div ng-controller="ParseController as vm" ng-bind-html="vm.parsedMsg"></div>
    
    <script src="https://code.angularjs.org/1.4.3/angular.js"></script>
    <script src="https://code.angularjs.org/1.4.3/angular-sanitize.js"></script>
    <script src="app.js"></script>
  </body>
</html>
The JavaScript part:
(function() {
  angular.module('app', ["ngSanitize"]).controller('ParseController', ParseController);

  function ParseController($scope, $parse) {
    this.libs = ['angular.js', 'angular-sanitize.js', 'bootstrap.css'];

    var template = $parse("libs[i]")

    var output = '';
    for (var i = 0; i < this.libs.length; i++) {
      output = output + '<li>' + template(this, {i: i}) + '</li>';
    }

    this.parsedMsg = 'The project uses <ul>' + output + '</ul>';
  }
})();
As you can see we pass {i: i} repeatedly as the second parameter, so that the expression libs[i] is always evaluated with the current value i. That means libs[0], libs[1], etc. The result looks like as follows:

There are some cool things you can do with $parse. I would like to only list three of them.

1) If the expression is assignable, the returned function (pre-compiled expression) will have an assign property. The assign property is a function that can be used to change the expression value on the given context, e.g. $scope. Example:
 
$parse('name').assign($scope, 'name2');
 
In the example, the value name on the $scope has been changed to name2.

2) If we have an object with properties that might be null, no JS errors will be thrown when using $parse. Instead of that, the result is set to undefined. In the example above, we had the property libs.angular.version. The result of
 
var version = $parse('libs.angular.version')(this);
 
is version = 1.4.3. If we would use a non exisiting property in the expression, e.g.
 
var version = $parse('libs.ember.version')(this);
 
the result would be version = undefined. AngularJS doesn't throw an exception.

3) Theoretically you can send any logic from backend to the client as string and evaluate the parsed string on the client. Example:
var backendString = 'sub(add(a, 1), b)';

var math = {
  add: function(a, b) {return a + b;},
  sub: function(a, b) {return a - b;}
};

var data = {
  a: 5,
  b: 2
};

var result = $parse(backendString)(math, data); // 4

Explicitly used $parse

AngularJS also uses $parse internally. The next example was taken from a book and slightly modified by me. It demonstrates a color picker with four sliders (three for colors and one for opacity).

The whole code: the HTML page, the color-picker directive and app.js are demonstrated in my last plunker. The page uses the color-picker directive:
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta content="IE=edge" http-equiv="X-UA-Compatible" />
  </head>
  <body ng-app="app">
    <h1>Magical $parse service</h1>
    
    <div ng-controller="MainController as vm">
      <color-picker init-r="255"
                    init-g="0"
                    init-b="0"
                    init-a="1.0"
                    on-change="vm.onColorChange(r,g,b,a)">
      </color-picker>
    </div>
    
    <script src="https://code.angularjs.org/1.4.3/angular.js"></script>
    <script src="app.js"></script>
  </body>
</html>
The directive's template colorPickerTemplate.html renders four input sliders, a live preview and current colors and opacity.
R:<input type="range"
         min="0" max="255" step="1"
         ng-model="r">
         <br>
G:<input type="range"
         min="0" max="255" step="1"
         ng-model="g">
         <br>
B:<input type="range"
         min="0" max="255" step="1"
         ng-model="b">
         <br>
A:<input type="range"
         min="0" max="1" step="0.01"
         ng-model="a">

<div style="width: 300px; height: 100px; margin-top:10px;
            background-color: rgba({{ r }}, {{ g }}, {{ b }}, {{ a }});">
</div>
{{ r }}, {{ g }}, {{ b }}, {{ a }}
The JavaScript part links all together. Whenever a color or opacity is changed, the Angular's $log service logs current colors and opacity in the browser dev. console. The current colors and opacity are also shown permanently as mentioned above.
(function() {
  angular.module('app', [])
    .controller('MainController', MainController)
    .directive('colorPicker', colorPickerDirective);

  function MainController($log) {
    this.onColorChange = function(r, g, b, a) {
      $log.log('onColorChange', r, g, b, a);
    };
  }

  function colorPickerDirective() {
    return {
        scope: {
          r:        '@initR',
          g:        '@initG',
          b:        '@initB',
          a:        '@initA',
          onChange: '&'
        },
        restrict: 'E',
        templateUrl: 'colorPickerTemplate.html',
        link: function(scope) {
          ['r', 'g', 'b', 'a'].forEach(function(value) {
              scope.$watch(value, function(newValue, oldValue) {
                  if (newValue !== oldValue) {
                      if (angular.isFunction(scope.onChange)) {
                          scope.onChange({
                            'r': scope.r,
                            'g': scope.g,
                            'b': scope.b,
                            'a': scope.a
                          });
                      }
                  }
              });
          });
        }
    };
  }
})();
But stop, where is the magic $parse here? The directive defines a parameter for an onchange callback via onChange: '&'. Behind the scenes, AngularJS parses the passed onchange string, in this case vm.onColorChange(r,g,b,a), and creates a function (discussed pre-compiled expression) which can be invoked with the desired context and locales. In the directive, we invoke this function with current values for colors r, g, b and opacity a.
scope.onChange({
    'r': scope.r,
    'g': scope.g,
    'b': scope.b,
    'a': scope.a
});

Relation to $interpolate and $eval

$eval is a method on a scope. It executes an expression on the current scope and returns the result. Example:
scope.a = 1;
scope.b = 2;
 
scope.$eval('a+b'); // result is 3
Internally, it uses $parse for their part.
$eval: function(expr, locals) {
    return $parse(expr)(this, locals);
}
Note, that the $eval method can not precompile expressions and be used repeatedly. The $parse, in contrast, can be invoked once in one place and its result can then be used repeatedly elsewhere. We have seen that in the second plunker. Here is another simple example to emphasize the difference to $eval:
var parsedExpression = $parse(...);

var scope1 = $scope.$new();
var scope2 = $scope.$new();

...

var result1 = parsedExpression(scope1);
var result2 = parsedExpression(scope2);
There is another high level service - $interpolate. By means of $interpolate you can do on-the-fly templating like well-known template engines Handlebars or Hogan do that. ES6 has similar template strings too. But take a look at one $interpolate example.
(function() {
  angular.module('app', []).controller('InterpolateController', InterpolateController);

  function InterpolateController($scope, $interpolate) {
    var template = $interpolate('Book {{title}} is published by {{publisher | uppercase}}');

    var bookData1 = {title: 'PrimeFaces Cookbook', publisher: 'Packt'};
    var bookData2 = {title: 'Spring in Action', publisher: 'Manning'};

    // execute the function "template" and pass it data objects to force interpolation
    var bookInfo1 = template(bookData1);
    var bookInfo2 = template(bookData2);

    // the result:
    // bookInfo1 = "PrimeFaces Cookbook is published by PACKT"
    // bookInfo1 = "Spring in Action is published by MANNING"
  }
})();
As you can see, the $interpolate service takes a string and returns a function which is a compiled template. Expressions in the passed string may have all allowable Angular's expression syntax. E.g. a pipe with filter as in the example {{publisher | uppercase}}. The function can be called again and again with different data objects. The $interpolate service uses $parse internally to evaluate individual expressions against the scope. In this regard, the $interpolate service is normally used as a string-based template language for strings containing multiple expressions. In contrast to $parse, the $interpolate is read only.

Sunday, June 14, 2015

Create source maps at project build time for JavaScript debugging

If you're doing front end web development, your web resources such as JavaScript and CSS files might be minificated, transpiled or compiled from a completely different language. If you now want to debug the generated code in the browser, you can not do that because the output code is obfuscated from the code you wrote. The solution is to use source maps. A good introduction to the source map can be found in the articles "Introduction to JavaScript Source Maps", "Enhance Your JavaScript Debugging with Cross-Browser Source Maps" and "An Introduction to Source Maps".

I will try to summarize the quintessence about the source maps and concentrate on JavaScript only. Generating CSS by LESS / SASS is interesting too, but it is not yet supported by my Maven plugin I will present in this blog post. How to use a source map? In order to use a source map, your browser development tools need to be able to find it. If your generated code is JavaScript, one way to let the development tools know where to look is to add a comment to the end of the generated code which defines the sourceMappingURL - the location of the source map. For example: //# sourceMappingURL=mylib.js.map or //# sourceMappingURL=/mypath/mylib.js.map or //# sourceMappingURL=http://sourcemaps/mylib.js.map. If you now open a development tool and the source map support is enabled, the browser will stream down the source map which points to the original file and show the original file instead of generated one (minificated, compiled, transpiled, etc.). Now, you can set a breakpoint in the original file and debug it as it would be delivered with you web application! Such debugging is possible due to the fact that a source map provides a way of mapping code within a generated file back to it's original position in a source file. I found a nice bild here to visualize the entire process.


Source maps are supported in all major browser that are shipped with built-in support for source maps. If you follow my links to the articles I mentioned above, you can see some examples for Internet Expoler 11, Firefox and Google Chrome. Chrome's Dev Tools enables the source maps support by default. Simple check if the checkbox "Enable JavaScript source maps" is enabled.


If you a fan of Firefox, you should use the Firefox' Web Console (Shift + Ctrl + K) and check if the same option is enabled in settings too. Please note that Firebug doesn't support debugging by source maps. You have to use the native Firefox' Web Console as I said. Internet Explorer 11 also rocks with source maps. It has even more features - you can add source map files from your local disk. Simple right-click on a generated (e.g. compressed) file and select "Choose source map". The article "Enhance Your JavaScript Debugging with Cross-Browser Source Maps" which I mentioned above, has a lot of picture for IE and debugging TypeScript files.

Source maps can be created during your build. If you work with Node.js and npm, the best tool is UglifyJS - a popular command line utility that allows you to combine and compress JavaScript files. If you work with Maven, you can use my Maven plugin for resource optimization I wrote a some years ago and just updated for supporting source maps. It uses the superb Google Closure Compiler which offers a support for source map creation and many other cool features. Please refer the documentation of the Maven plugin to see how to set the various source map configuration options. The simplest configuration which we also use in the current PrimeFaces Extensions release looks like as follows:
<plugin>
    <groupId>org.primefaces.extensions</groupId>
    <artifactId>resources-optimizer-maven-plugin</artifactId>
    <version>2.0.0</version>
    <configuration>
        <sourceMap>
            <create>true</create>
            <outputDir>${project.basedir}/src/sourcemap/${project.version}</outputDir>
            <sourceMapRoot>
              https://raw.githubusercontent.com/primefaces-extensions/core/master/src/sourcemap/${project.version}/
            </sourceMapRoot>
        </sourceMap>
    </configuration>
    <executions>
        <execution>
            <id>optimize</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>optimize</goal>
            </goals>
        </execution>
    </executions>
</plugin>
By this way, only compressed JavaScript files will be packaged within released JAR file. Uncompressed files are not within the JAR. The JAR is smaller and free from redundant stuff. For the PrimeFaces Extensions, the source map and uncompressed files are checked in below the project root. For example, the folder with source maps and original files for the current release 3.2.0 is located here: https://github.com/primefaces-extensions/core/tree/master/src/sourcemap/3.2.0 That means, a compressed file, say timeline.js, has the following line at the end:

//# sourceMappingURL=https://raw.githubusercontent.com/primefaces-extensions/core/master/src/sourcemap/3.2.0/timeline.js.map

The source map timeline.js.map has the content (I truncated some long lines):
{
  "version":3,
  "file":"timeline.js",
  "lineCount":238,
  "mappings":"A;;;;;;;;;;;;;;;;;;;;AA4DqB,WAArB,GAAI,MAAOA,MAAX,GACIA,KADJ,CACY,EADZ,CAUsB,YAAtB,GAAI,...
  "sources":["timeline.source.js"],
  "names":["links","google","undefined","Array","prototype","indexOf","Array.prototype.indexOf",...]
}
It would be probably better to bring these files to a CDN, like cdnjs, but CDNs are not really intended for source maps. Another option would be a PrimeFaces repository. We will see how to handle that in the future. The next picture demonstrates how the debugging for the compressed JS file timeline.js looks in my Firefox.


Due to the Firefox built-in source map support we see the uncompressed JS file timeline.source.js. I set a breakpoint on the line with the if-statement if (index < 0). After that I clicked on an event in the Timeline component. The breakpoint was jumped up. Now, I can debug step by step and see my local and global variables on the right side. As you probably see, the variable index is shown as a (I marked it red as var index). This is a shortcoming of the current source map specification. You can read this discussion for more details.

Again, keep in mind - the source maps and original files will be only loaded when you open up the browser dev. tools and enable this support explicitly. If the dev. tools has identified that a source map is available, it will be fetched along with referenced source file(s). If a source map file is not available, you will see a 404 "not found message" in the dev. tool (not bad at all in my opinion).

That's all. My next posts will be about AngularJS and less about JSF. Stay tuned.

Wednesday, June 10, 2015

PrimeFaces Extensions 3.2.0 released

Dear PrimeFaces community,

PrimeFaces Extensions 3.2.0 has been released! This is a maintenance release which is built on top of PrimeFaces 5.2. Closed issues are available on GitHub.

Some notes to the two important changes:
  • pe:ajaxErrorHandler was removed in favor of p:ajaxExceptionHandler. It was buggy and not working in the prev. release.
  • Uncompressed JS files are not delivered anymore within JAR files. The compressed JS files contain //# sourceMappingURL=... which points to the appropriate source maps and uncompressed files for debug purpose. The source maps and uncompressed files are checked in direct in the GitHub and can be fetched from there. That means, uncompressed files have something like at the end:
    //# sourceMappingURL=https://raw.githubusercontent.com/primefaces-extensions/core/master/src/sourcemap/3.2.0/primefaces-extensions.js.map

    More info about source map is coming soon in my blog and the Wiki page of the Maven plugin for resource optimization.
The deployed showcase will be available soon as usually at http://primefaces.org/showcase-ext/views/home.jsf.

Have fun!

Friday, May 29, 2015

PrimeFaces Cookbook Second Edition has been published

PrimeFaces Cookbook Second Edition was published today. This is an updated second edition of the first PrimeFaces book ever published. PrimeFaces Cookbook Second Edition covers over 100 effective recipes for PrimeFaces 5.x which this leading component suite offers you to boost JSF applications - from AJAX basics, theming, i18n support and input components to advanced usage of datatable, menus, drag-&-drop, charts, client-side validation, dialog framework, exception handling, responsive layout, and more.


I have updated the book's homepage with a new table of contents. There are 11 chapters and more than 380 pages. You can download the book's code, clone the project on GitHub, compile and run it. Please follow the instructions on the GitHub.

I would like to thank my family, especially my wife, Veronika; our advisers from Packt Publishing, Llewellyn Rozario and Ajinkya Paranjape, our reviewers, the PrimeFaces project lead Çağatay Çivici and JSF specification lead Ed Burns. These people accompanied us during the entire writing process and made the publication of the book possible with their support, suggestions, and reviews. Thanks a lot!

Wednesday, April 22, 2015

PrimeFaces Extensions 3.1.0 released

Today, we released the PrimeFaces Extensions 3.1.0. It is built on top of PrimeFaces 5.2 and is fully compatible with PrimeFaces 5.2.

Closed issues are available on the GitHub. Please consider some enhancements in the existing components like Timeline, DynaForm, InputNumber and CKEditor.

The new deployed showcase will be available soon as usually here. The next release will be a maintenance release again.

Have fun!