tag:blogger.com,1999:blog-84920598421423564882024-03-13T05:26:13.058+01:00Thoughts on software development"The best is yet to come"Oleg Varaksinhttp://www.blogger.com/profile/13872270134068047346noreply@blogger.comBlogger154125tag:blogger.com,1999:blog-8492059842142356488.post-732562705475560252016-08-27T16:31:00.000+02:002016-08-27T16:32:16.798+02:00Switched to MediumThis is my last post on Blogger. I have decided to switch to <a href="https://medium.com/">Medium</a>, a great and simple blogging platform.<br />
<br />
My future post will be available here: <a href="https://medium.com/@OlegVaraksin">https://medium.com/@OlegVaraksin</a><br />
<br />
Thanks!Oleg Varaksinhttp://www.blogger.com/profile/13872270134068047346noreply@blogger.com0tag:blogger.com,1999:blog-8492059842142356488.post-69662064461082146692016-05-30T22:30:00.003+02:002016-05-30T22:30:42.135+02:00Lazy inter-module communication with require() and webpack<b>Motivation</b><br />
<br />
CommonJS' modules can be loaded on demand with <span style="color: orange;">require.ensure(...)</span>. Example:
<br />
<pre class="brush:js">require.ensure(["module-a"], function(require) {
var a = require("module-a");
// module-a can be used now ...
});
</pre>
The well-known module bundler <a href="https://webpack.github.io/">Webpack</a> supports this syntax for loading modules on demand. Such lazy loaded module(s) define a <a href="https://webpack.github.io/docs/code-splitting.html">split point</a>. Split points split the codebase into "chunks" (separate JavaScript files) which are loaded on demand. This feature allows to keep the initial download small and only download the code when it's requested.<br />
<br />
Webpack performs a static analysis of the code at the project build time. Dynamic information is only available at runtime and not available at build time. You have to define your modules as constants. This leads to the problem. The following code will not work:
<br />
<pre class="brush:js">var modA = "module-a";
require.ensure([modA], function(require) {
var a = require("module-a");
// module-a can be used now ...
});
</pre>
Webpack says something like: <span style="color: orange;">Error: Module not found. A dependency to an entry point is not allowed.</span><br />
<br />
Theoretically you can use <a href="https://webpack.github.io/docs/context.html">require.context</a>, but this needs some parts of module's path as constants too. Now, imagine you develop a modular UI library and would like to provide some callbacks for certain events (event handlers). Users of your library use it as a third-party library. They want to register their custom callback functions from their own modules. And they want to be called lazy, on demand, when an event occurs. You have many users and your library doesn't know about custom modules of course. That means, you can not hard-code module's path and function's name a priori. What to do?<br />
<br />
<b>Solution</b><br />
<br />
<a href="https://github.com/ova2/dynamic-require-poc">This POC on GitHub</a> demonstrates how to use truly dynamic require with webpack. It simulates third-party and own modules. The project structure:
<br />
<pre class="brush:js">index.html // some HTML template from the third-party UI library
external-modules // third-party library with CommonJS modules
own-modules // some library with CommonJS modules which uses the third-party library
common-modules // simple utility modules
</pre>
The modules in external-modules don't know about own-modules. Modules in the own-modules import modules from the external-modules. The most important webpack loader we use in this POC is <a href="https://github.com/webpack/bundle-loader">bundle loader for webpack</a>. This loader creates a special function with required module which can be executed lazily. The required module gets loaded when the function is executed.<br />
<br />
The HTML template in the POC, backed by the third-party (external) modules, look like as follows (only short snippet):
<br />
<pre class="brush:html"><button data-init="button" data-onclick='["ownModules.button", "alertSync"]'>
Try sync. call (ok)
</button>
<p></p>
<button data-init="button" data-onclick='["ownModules.button", "alertAsyncValid"]'>
Try async. call (ok)
</button>
<p></p>
<button data-init="button" data-onclick='["ownModules.button", "alertAsyncInvalid"]'>
Try async. call (error)
</button>
</pre>
The full code can be found in <span style="color: orange;">index.xhtml</span>. The callback functions are defined as values of <span style="color: orange;">data-*</span> attributes. Example: <span style="color: orange;">data-onclick='["ownModules.button", "alertSync"]'</span>. Here, the function <span style="color: orange;">alertSync</span> from the namespace <span style="color: orange;">ownModules.button</span> wants to be called when the button is clicked. The namespace is a simple JavaScript object defined in the global window scope.<br />
<br />
The module's functions in the folder <span style="color: orange;">own-modules</span> returns <span style="color: orange;">Promises</span>. Promises allow asynchronous callbacks. In the POC, the NPM module <a href="https://www.npmjs.com/package/promise-light">promise light</a> is used. If you have jQuery in your web app, you can use <a href="https://api.jquery.com/category/deferred-object">jQuery Deferred Object</a> as well because it provides the same functionality. The sample implementation of the <span style="color: orange;">button.js</span> looks like as
<br />
<pre class="brush:js">var Promise = require('promise-light');
module.exports = {
alertSync: function (element) {
document.getElementById('output').innerHTML = 'Clicked button. Sync. call is OK';
return Promise.resolve('OK');
},
alertAsyncValid: function (element) {
return new Promise(function setup(resolve, reject) {
setTimeout(function () {
document.getElementById('output').innerHTML = 'Clicked button. Async. call is OK';
resolve('OK');
}, 1000);
});
},
alertAsyncInvalid: function (element) {
return new Promise(function setup(resolve, reject) {
setTimeout(function () {
document.getElementById('output').innerHTML = 'Clicked button. Async. call has ERROR';
reject('ERROR');
}, 1000);
});
}
};
</pre>
The external modules should be bootstrapped by the own modules. The bootstrapping occurs in the file <span style="color: orange;">entry.js</span> which acts as an entry point in the webpack configuration.
<br />
<pre class="brush:js">var objectifier = require("./../common-modules/objectifier");
var bootstrap = require("./../external-modules/bootstrap");
document.addEventListener("DOMContentLoaded", function (event) {
// initialize external modules
bootstrap.bootstrap();
// lazy load own modules (s. https://github.com/webpack/bundle-loader)
var lazyLoadedButton = require("bundle?lazy!./button");
var lazyLoadedCheckbox = require("bundle?lazy!./checkbox");
// and put them under namespaces ownModules.button and ownModules.checkbox resp.
objectifier.set('ownModules.button', lazyLoadedButton);
objectifier.set('ownModules.checkbox', lazyLoadedCheckbox);
});
</pre>
As you can see, the bundle loader is applied to the own modules. The returned functions are saved under arbitrary namespaces in order to be executed later in external modules. Note: the <span style="color: orange;">objectifier</span> is just a CommonJS module porting of the beautiful <a href="https://davidwalsh.name/nested-objects">getter and setter implementation for nested objects</a>.
The <span style="color: orange;">button.js</span> in the <span style="color: orange;">external-modules</span> registers an onlick event handler for all HTML elements having the <span style="color: orange;">data-init="button"</span> attribute.
<br />
<pre class="brush:js">var lazyloader = require("./lazyloader");
module.exports = {
init: function () {
var elements = document.querySelectorAll('[data-init="button"]');
for (var i = 0; i < elements.length; i++) {
(function () {
var element = elements[i];
// onlick event handler
var onclick = function () {
// so something module specific ...
// execute function defined via data-onclick attribute if it's defined,
// e.g. data-onclick='["ownModules.button", "alertSync"]'
lazyloader.execute(element, 'data-onclick',
function resolved(value) {
alert(value);
}, function rejected(error) {
alert(error);
});
};
element.addEventListener("click", onclick);
})();
}
return elements;
},
doSomething: function () {
// ...
}
};
</pre>
The core logic for the event handling is encapsulated in the <span style="color: orange;">lazyloader.js</span>.
<br />
<pre class="brush:js">/**
Loads modules specified via data-* attributes and executes the specified function.
HTML-Example:
<button data-init="button" data-onclick='["ownModules.button", "alertSync"]'>
...
</button>
The function ownModules.button.alertSync(button) will be executed.
*/
var objectifier = require("./../common-modules/objectifier");
module.exports = {
/**
* Executes the specified synchronous or asynchronous function from the specified module
* and invokes resolved or rejected callbacks respectively.
* The function should return a promise.
*
* @param element HTML element where data-* is defined
* @param data value of data-* as string
* @param resolvedCallback callback which gets executed when the returned promise is fullfilled
* @param rejectedCallback callback which gets executed when the returned promise is rejected
*/
execute: function (element, data, resolvedCallback, rejectedCallback) {
var strData = element.getAttribute(data);
if (strData) {
var objData = JSON.parse(strData);
var module = objData[0];
var func = objData[1];
if (module && objectifier.exists(module) && func) {
// module and function exist ==> load the module
objectifier.get(module)(function (module) {
// execute the specified function from the module.
// return value is a promise (see https://www.npmjs.com/package/promise-light)
module[func](element).then(
function resolved(value) {
resolvedCallback(value);
},
function rejected(error) {
rejectedCallback(error);
});
});
}
}
}
};
</pre>
It executes the specified function from the specified module. The caller receives a promise. If the promise gets resolved, the first function in <span style="color: orange;">.then(...)</span> is executed. If the promise gets rejected, the second function in <span style="color: orange;">.then(...)</span> is executed. The synchronous or asynchronous function from the own modules can control whether it resolves or rejects the promise. The caller can decide then what it should do in both cases. For instance, assume you got an accordion widget which belongs to a third-party library. One interesting case could be the validation of the content of an open accordion tab when the tab's header is clicked by the user. A custom function could validate the tab content on such click. In case of a successful validation, the clicked tab can be closed. Otherwise, the tab should stay open.<br />
<br />
<b>Screens</b><br />
<br />
The initial load doesn't fetch chunks from the own modules.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-ZOhOYHZJV0c/V0yisGr5XXI/AAAAAAAAAqQ/K8Fw9UucjiMXFWO8Bn5kQ5a61GqTu2hgwCLcB/s1600/init-load.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="497" src="https://2.bp.blogspot.com/-ZOhOYHZJV0c/V0yisGr5XXI/AAAAAAAAAqQ/K8Fw9UucjiMXFWO8Bn5kQ5a61GqTu2hgwCLcB/s640/init-load.png" width="640" /></a></div>
<br />
Click on a button triggers the load of the first chunk.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-tMyGOlgU0Cg/V0yiziTAO_I/AAAAAAAAAqU/aTYrbJcZFKQNimcsCdmEOfaorWgZN0_sQCLcB/s1600/chunk-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="492" src="https://4.bp.blogspot.com/-tMyGOlgU0Cg/V0yiziTAO_I/AAAAAAAAAqU/aTYrbJcZFKQNimcsCdmEOfaorWgZN0_sQCLcB/s640/chunk-1.png" width="640" /></a></div>
<br />
Click on a checkbox triggers the load of the second chunk.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-vbDKIohRpGQ/V0yi4Bi_qRI/AAAAAAAAAqY/dV9n3GhRWnIvqIbfHqnu_1OR6Ts50t6SgCLcB/s1600/chunk-2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="494" src="https://1.bp.blogspot.com/-vbDKIohRpGQ/V0yi4Bi_qRI/AAAAAAAAAqY/dV9n3GhRWnIvqIbfHqnu_1OR6Ts50t6SgCLcB/s640/chunk-2.png" width="640" /></a></div>
<br />Oleg Varaksinhttp://www.blogger.com/profile/13872270134068047346noreply@blogger.com2tag:blogger.com,1999:blog-8492059842142356488.post-61555534734632987852016-05-15T18:19:00.002+02:002016-05-17T00:21:34.847+02:00NPM module Browser-Sync in Java / Web projects<a href="https://www.browsersync.io/">Browser-Sync</a> is a handy Node.js based NPM module which can be used for a faster web development. Browser-Sync synchronizes file changes and interactions across many devices. The most important feature is the live reloading. We can use the Browser-Sync in Java / Web projects too. Cagatay Civici created a great <a href="http://blog.primefaces.org/?p=3912">video tutorial</a> how to use this module with the <a href="http://www.primefaces.org/showcase/">PrimeFaces showcase</a>. The PrimeFaces showcase has a built-in Jetty server which looks to the source folder <span style="color: orange;">src/main/webapp</span> as the web context root. After the Browser-Sync installation via the Node.js package manager NPM
<br />
<pre class="brush:text">
npm install -g browser-sync
</pre>
we have to start the Jetty server for the PrimeFaces showcase at <span style="color: orange;">http://localhost:8080/showcase</span>. Afther that we can use this URL as proxy for a built-in server included in the Browser-Sync. The Browser-Sync should listen to changes under <span style="color: orange;">src/main/webapp
</span><br />
<pre class="brush:text">
browser-sync start --proxy "http://localhost:8080/showcase" --files "src/main/webapp/**/*"
</pre>
As result, a default browser will be started at <span style="color: orange;">http://localhost:3000/showcase</span> with the PrimeFaces showcase. The port <span style="color: orange;">3000</span> is the default port for the Browser-Sync.<br />
<br />
This approach works well until you have made changes in Java files. Java files are not web resources under <span style="color: orange;">src/main/webapp</span>. In Maven projects they located under <span style="color: orange;">src/main/java</span>. That means, changes in Java files will not be recognized. The solution is <span style="color: orange;">exploded WAR</span>. An exploded WAR is a directory where the web application gets deployed from. Every application server can deploy an exploded WAR. For Maven projects, this directory is normally <span style="color: orange;">target/webapp</span>. The <a href="https://maven.apache.org/plugins/maven-war-plugin/exploded-mojo.html">Maven WAR plugin</a> has the goal <span style="color: orange;">war:exploded</span> too. If you have an IDE, you can configure your web application as an exploded WAR. I have blogged about <a href="http://ovaraksin.blogspot.de/2013/10/hot-deployment-with-intellij-idea.html">Hot Deployment with IntelliJ IDEA</a> a couple of years ago. In IntelliJ, you can automatically copy changed files (CSS, JS, HTML resources and compiled Java files) to the directory for the exploded WAR.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-coLNB_Bmy6M/VzigUNyImgI/AAAAAAAAAp8/p8SJdF_xecYvza8gZu1wFmjsYPPVOAJfQCLcB/s1600/run-config.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="363" src="https://2.bp.blogspot.com/-coLNB_Bmy6M/VzigUNyImgI/AAAAAAAAAp8/p8SJdF_xecYvza8gZu1wFmjsYPPVOAJfQCLcB/s640/run-config.png" width="640" /></a></div>
<br />
Now, if you refresh the browser manually, you will see the changes in Java classes too. But we want to do this better. We want to use the highly praised live reloading! To achieve this goal, set files to be watched as follows<br />
<pre class="brush:text">
browser-sync start --proxy "http://localhost:8080/showcase" --files "target/classes/**/*.class, target/webapp/**/*"
</pre>
The output looks like
<br />
<pre class="brush:text">[BS] Proxying: http://localhost:8080
[BS] Access URLs:
---------------------------------------------------------------------
Local: http://localhost:3000/showcase
External: http://192.168.178.27:3000/showcase
---------------------------------------------------------------------
UI: http://localhost:3001
UI External: http://192.168.178.27:3001
---------------------------------------------------------------------
</pre>
Now, I can do any changes in all important files and see something like in the console
<br />
<pre class="brush:text">
[BS] Watching files...
[BS] File changed: target\webapp\META-INF\MANIFEST.MF
[BS] File changed: target\webapp\WEB-INF\classes\some\showcase\bean\SomeBean.class
[BS] File changed: target\webapp\views\someView.xhtml
[BS] File changed: target\webapp\META-INF\MANIFEST.MF
</pre>
The browser page gets updated by the Browser-Sync automatically (which uses WebSockets by the way). If you have trouble with your IDE, you can use <a href="http://gulpjs.com/">Gulp</a> to rescue! Here my idea for a <span style="color: orange;">gulpfile.js</span> (Gulp 4).
<br />
<pre class="brush:js">var browsersync = require('browser-sync').create();
// init Browser-Sync
gulp.task('browser-sync', function() {
browsersync.init({
proxy: "http://localhost:8080/showcase"
});
});
// compile changed Java files by Maven "mvn compile"
// compiled classes will be transfered to target/classes automatically
gulp.task('java', function () {
// use 'spawn' to execute command using Node.js
var spawn = require('child_process').spawn;
// set the working directory to project root where gulpfile.js exists
process.chdir(__dirname);
// run "mvn compile"
var child = spawn('mvn', ['compile']);
// print output
child.stdout.on('data', function(data) {
if (data) {
console.log(data.toString());
}
});
});
// copy changes from src/main/webapp to target/webapp
gulp.task('webapp', function () {
return gulp.src('src/main/webapp/**/*', {since: gulp.lastRun('webapp')})
.pipe(gulp.dest('target/webapp'));
});
// watch files for changes
gulp.task('watch', function () {
gulp.watch('src/main/java/**/*.java', gulp.series('java'));
gulp.watch('src/main/webapp/**/*', gulp.series('webapp'));
gulp.watch(['target/classes/**/*.class', 'target/webapp/**/*'], browsersync.reload);
});
// default task
gulp.task('default', gulp.series('browser-sync', 'watch'));
</pre>
This file should be placed in the project root folder. Now, you are able to execute the command (Gulp should be installed of course)
<br />
<pre class="brush:text">
gulp
</pre>
and enjoy the live reloading! Please consider, the Gulp <span style="color: orange;">java</span> task. Maven only compiles changed files. It works very fast! Without changes there are nothing to be compiled - the output of the <span style="color: orange;">mvn compile</span> looks like:
<br />
<pre class="brush:text">
[INFO] Nothing to compile - all classes are up to date
</pre>
If we make a change in one Java file, the output looks like:
<br />
<pre class="brush:text">
[INFO] Compiling 1 source file to <path>\showcase\target\classes
</pre>
<u>Note</u>: The server should run in <span style="color: orange;">reloadable</span> mode. E.g. Tomcat has a <span style="color: orange;">reloadable</span> option in <a href="https://tomcat.apache.org/tomcat-7.0-doc/config/context.html">context.xml</a>. Set it to true to force monitoring classes in /<span style="color: orange;">WEB-INF/classes/</span> and <span style="color: orange;">/WEB-INF/lib</span> for changes and automatically reload the web application if a change is detected. JBoss has this feature automatically if you start it in the debug mode.<br />
<br />
I can also imagine some complex Gulp tasks, such as compiling Java classes in dependent JAR files, build JARs and copy them to the <span style="color: orange;">WEB-INF/lib</span> folder of the exploded WAR.Oleg Varaksinhttp://www.blogger.com/profile/13872270134068047346noreply@blogger.com0tag:blogger.com,1999:blog-8492059842142356488.post-88565997007093274522016-04-03T10:58:00.003+02:002016-05-10T02:11:51.848+02:00Clean architecture of Selenium testsIn this blog post, I would like to introduce a clean architecture for Selenium tests with best design patterns: page object, page element (often called HTML wrapper) and self-developed, very small but smart framework. The architecture is not restricted to Java which is used in the examples and can be applied to Selenium tests in any other language as well.<br />
<br />
<b>Definitions and relations.</b><br />
<br />
<span style="color: orange;">Page Object</span>. A page object encapsulates the behavior of a web page. There is one page object per web page that abstracts the page's logic to the outside. That means, the interaction with the web page is encapsulated in the page object. Selenium's <span style="color: orange;">By</span> locators to find elements on the page are not disclosed to the outside as well. The page object's caller should not be busy with the <span style="color: orange;">By</span> locators, such as <span style="color: orange;">By.id</span>, <span style="color: orange;">By.tageName</span>, <span style="color: orange;">By.cssSelector</span>, etc. Selenium test classes operate on page objects. Take an example from a web shop: the page object classes could be called e.g. <span style="color: orange;">ProductPage</span>, <span style="color: orange;">ShoppingCartPage</span>, <span style="color: orange;">PaymentPage</span>, etc. These are always classes for the whole web pages with their own URLs.<br />
<br />
<span style="color: orange;">Page Element</span> (aka <span style="color: orange;">HTML Wrapper</span>). A page element is another subdivision of a web page. It represents a HTML element and encapsulates the logic for the interaction with this element. I will term a page element as HTML wrapper. HTML wrappers are reusable because several pages can incorporate the same elements. For instance, a HTML wrapper for Datepicker can provide the following methods (API): "set a date into the input field", "open the calendar popup", "choose given day in the calendar popup", etc. Other HTML wrappes would be e.g. Autocomplete, Breadcrumb, Checkbox, RadioButton, MultiSelect, Message, ... A HTML Wrapper can be composite. That means, it can consist of multiple small elements. For instance, a product catalog consists of products, a shopping cart consists of items, etc. Selenium's <span style="color: orange;">By</span> locators for the inner elements are encapsulated in the composite page element.<br />
<br />
Page Object and HTML Wrappers as design patterns were <a href="http://martinfowler.com/bliki/PageObject.html">described by Martin Fowler</a>.<br />
<br />
<b>The skeletal structure of a Selenium test class.</b><br />
<br />
A test class is well structured. It defines the test sequence in form of single process steps. I suggest the following structure:
<br />
<pre class="brush:java">public class MyTestIT extends AbstractSeleniumTest {
@FlowOnPage(step = 1, desc = "Description for this method")
void flowSomePage(SomePage somePage) {
...
}
@FlowOnPage(step = 2, desc = "Description for this method")
void flowAnotherPage(AnotherPage anotherPage) {
...
}
@FlowOnPage(step = 3, desc = "Description for this method")
void flowYetAnotherPage(YetAnotherPage yetAnotherPage) {
...
}
...
}
</pre>
The class <span style="color: orange;">MyTestIT</span> is an JUnit test class for an integration test. <span style="color: orange;">@FlowOnPage</span> is a method annotation for the test logic on a web page. The <span style="color: orange;">step</span> parameter defines a serial number in the test sequence. The numeration starts with 1. That means, the annotated method with the step = 1 will be processed before the method with the step = 2. The second parameter <span style="color: orange;">desc</span> stands for description what the method is doing.
<br />
<pre class="brush:java">@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FlowOnPage {
int step() default 1;
String desc();
}
</pre>
The annotated method is invoked with a page object as method parameter. A switch to the next page normally occurs per click on a button or link. The developed framework should make sure that the next page is completely loaded before the annotated method with next step gets called. The next diagram illustrates the relationship between a test class, page objects and HTML wrappers.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-CdREdHFJ1Hw/VwDVZaHDFBI/AAAAAAAAAo4/r30Bj8XHwgQA9H8koAY0FLPCHBzVmsOVQ/s1600/Selenium.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://3.bp.blogspot.com/-CdREdHFJ1Hw/VwDVZaHDFBI/AAAAAAAAAo4/r30Bj8XHwgQA9H8koAY0FLPCHBzVmsOVQ/s1600/Selenium.png" /></a></div>
<br />
But stop. Where is the JUnit method annotated with <span style="color: orange;">@Test</span> and where is the logic for the parsing of <span style="color: orange;">@FlowOnPage</span> annotation? That code is hidden in the super class <span style="color: orange;">AbstractSeleniumTest</span>.
<br />
<pre class="brush:java">public abstract class AbstractSeleniumTest {
// configurable base URL
private final String baseUrl = System.getProperty("selenium.baseUrl", "http://localhost:8080/contextRoot/");
private final WebDriver driver;
public AbstractSeleniumTest() {
// create desired WebDriver
driver = new ChromeDriver();
// you can also set here desired capabilities and so on
...
}
/**
* The single entry point to prepare and run test flow.
*/
@Test
public void testIt() throws Exception {
LoadablePage lastPageInFlow = null;
List <Method> methods = new ArrayList<>();
// Seach methods annotated with FlowOnPage in this and all super classes
Class c = this.getClass();
while (c != null) {
for (Method method: c.getDeclaredMethods()) {
if (method.isAnnotationPresent(FlowOnPage.class)) {
FlowOnPage flowOnPage = method.getAnnotation(FlowOnPage.class);
// add the method at the right position
methods.add(flowOnPage.step() - 1, method);
}
}
c = c.getSuperclass();
}
for (Method m: methods) {
Class<?>[] pTypes = m.getParameterTypes();
LoadablePage loadablePage = null;
if (pTypes != null && pTypes.length > 0) {
loadablePage = (LoadablePage) pTypes[0].newInstance();
}
if (loadablePage == null) {
throw new IllegalArgumentException("No Page Object as parameter has been found for the method " +
m.getName() + ", in the class " + this.getClass().getName());
}
// initialize Page Objects Page-Objekte and set parent-child relationship
loadablePage.init(this, m, lastPageInFlow);
lastPageInFlow = loadablePage;
}
if (lastPageInFlow == null) {
throw new IllegalStateException("Page Object to start the test was not found");
}
// start test
lastPageInFlow.get();
}
/**
* Executes the test flow logic on a given page.
*
* @throws AssertionError can be thrown by JUnit assertions
*/
public void executeFlowOnPage(LoadablePage page) {
Method m = page.getMethod();
if (m != null) {
// execute the method annotated with FlowOnPage
try {
m.setAccessible(true);
m.invoke(this, page);
} catch (Exception e) {
throw new AssertionError("Method invocation " + m.getName() +
", in the class " + page.getClass().getName() + ", failed", e);
}
}
}
@After
public void tearDown() {
// close browser
driver.quit();
}
/**
* This method is invoked by LoadablePage.
*/
public String getUrlToGo(String path) {
return baseUrl + path;
}
public WebDriver getDriver() {
return driver;
}
}
</pre>
As you can see, there is only one test method <span style="color: orange;">testIt</span> which parses the annotations, creates page objects with relations and starts the test flow.<br />
<br />
<b>The structure of a Page Object.</b><br />
<br />
Every page object class inherits from the class <span style="color: orange;">LoadablePage</span> which inherits again from the Selenium's class <a href="https://selenium.googlecode.com/svn/trunk/docs/api/java/org/openqa/selenium/support/ui/LoadableComponent.html">LoadableComponent</a>. A good explanation for <span style="color: orange;">LoadableComponent</span> is available in this well written article: <a href="http://blog.wedoqa.com/2014/10/simple-and-advanced-usage-of-loadablecomponent/">Simple and advanced usage of LoadableComponent</a>. <span style="color: orange;">LoadablePage</span> is our own class, implemented as follows:
<br />
<pre class="brush:java">import org.openqa.selenium.support.ui.WebDriverWait;
import org.junit.Assert;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.LoadableComponent;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Method;
import java.util.List;
public abstract class LoadablePage<T extends LoadableComponent<T>> extends LoadableComponent<T> {
private final static Logger LOGGER = LoggerFactory.getLogger(LoadablePage.class);
private AbstractSeleniumTest seleniumTest;
private String pageUrl;
private Method method;
private LoadablePage parent;
/**
* Init method (invoked by the framework).
*
* @param seleniumTest instance of type AbstractSeleniumTest
* @param method to be invoked method annotated with @FlowOnPage
* @param parent parent page of type LoadablePage
*/
void init(AbstractSeleniumTest seleniumTest, Method method, LoadablePage parent) {
this.seleniumTest = seleniumTest;
this.pageUrl = seleniumTest.getUrlToGo(getUrlPath());
this.method = method;
this.parent = parent;
PageFactory.initElements(getDriver(), this);
}
/**
* Path of the URL without the context root for this page.
*
* @return String path of the URL
*/
protected abstract String getUrlPath();
/***
* Specific check which has to be implemented by every page object.
* A rudimentary check on the basis of URL is undertaken by this class.
* This method is doing an extra check if the page has been proper loaded.
*
* @throws Error thrown when the check fails
*/
protected abstract void isPageLoaded() throws Error;
@Override
protected void isLoaded() throws Error {
// min. check against the page URL
String url = getDriver().getCurrentUrl();
Assert.assertTrue("You are not on the right page.", url.equals(pageUrl));
// call specific check which has to be implemented on every page
isPageLoaded();
}
@Override
protected void load() {
if (parent != null) {
// call the logic in the parent page
parent.get();
// parent page has navigated to this page (via click on button or link).
// wait until this page has been loaded.
WebDriverWait wait = new WebDriverWait(getDriver(), 20, 250);
wait.until(new ExpectedCondition<Boolean> () {
@Override
public Boolean apply(WebDriver d) {
try {
isLoaded();
return true;
} catch (AssertionError e) {
return false;
}
}
});
} else {
// Is there no parent page, the page should be navigated directly
LOGGER.info("Browser: {}, GET {}", getDriver(), getPageUrl());
getDriver().get(getPageUrl());
}
}
/**
* Ensure that this page has been loaded and execute the test code on the this page.
*
* @return T LoadablePage
*/
public T get() {
T loadablePage = super.get();
// execute flow logic
seleniumTest.executeFlowOnPage(this);
return loadablePage;
}
/**
* See {@link WebDriver#findElement(By)}
*/
public WebElement findElement(By by) {
return getDriver().findElement(by);
}
/**
* See {@link WebDriver#findElements(By)}
*/
public List<WebElement> findElements(By by) {
return getDriver().findElements(by);
}
public WebDriver getDriver() {
return seleniumTest.getDriver();
}
protected String getPageUrl() {
return pageUrl;
}
Method getMethod() {
return method;
}
}
</pre>
As you can see, every page object class needs to implement two abstract methods:
<br />
<pre class="brush:java">/**
* Path of the URL without the context root for this page.
*
* @return String path of the URL
*/
protected abstract String getUrlPath();
/***
* Specific check which has to be implemented by every page object.
* A rudimentary check on the basis of URL is undertaken by the super class.
* This method is doing an extra check if the page has been proper loaded.
*
* @throws Error thrown when the check fails
*/
protected abstract void isPageLoaded() throws Error;
</pre>
Now I would like to show the code for a concrete page object and a test class which tests the <a href="http://fahrplan.sbb.ch/bin/query.exe/en">SBB Ticket Shop</a>, so that readers can acquire a taste for testing with page objects. The page object <span style="color: orange;">TimetablePage</span> contains HTML wrappers for basic elements.
<br />
<pre class="brush:java">public class TimetablePage extends LoadablePage<TimetablePage> {
@FindBy(id = "...")
private Autocomplete from;
@FindBy(id = "...")
private Autocomplete to;
@FindBy(id = "...")
private Datepicker date;
@FindBy(id = "...")
private TimeInput time;
@FindBy(id = "...")
private Button search;
@Override
protected String getUrlPath() {
return "pages/fahrplan/fahrplan.xhtml";
}
@Override
protected void isPageLoaded() throws Error {
try {
assertTrue(findElement(By.id("shopForm_searchfields")).isDisplayed());
} catch (NoSuchElementException ex) {
throw new AssertionError();
}
}
public TimetablePage typeFrom(String text) {
from.setValue(text);
return this;
}
public TimetablePage typeTo(String text) {
to.setValue(text);
return this;
}
public TimetablePage typeTime(Date date) {
time.setValue(date);
return this;
}
public TimetablePage typeDate(Date date) {
date.setValue(date);
return this;
}
public TimetablePage search() {
search.clickAndWaitUntil().ajaxCompleted().elementVisible(By.cssSelector("..."));
return this;
}
public TimetableTable getTimetableTable() {
List<WebElement> element = findElements(By.id("..."));
if (element.size() == 1) {
return TimetableTable.create(element.get(0));
}
return null;
}
}
</pre>
In the page object, HTML wrappers (simple or composite) can be created either by the <span style="color: orange;">@FindBy</span>,<span style="color: orange;"> @FindBys</span>, <span style="color: orange;">@FindAll</span> annotations or dynamic on demand, e.g. as <span style="color: orange;">TimetableTable.create(element)</span> where <span style="color: orange;">element</span> is the underlying <span style="color: orange;">WebElement</span>. Normally, the annotations don't work with custom elements. They only work with the Selenium's <span style="color: orange;">WebElement</span> per default. But it is not difficult to get them working with the custom elements too. You have to implement a custom <span style="color: orange;">FieldDecorator</span> which extends <a href="https://selenium.googlecode.com/git/docs/api/java/org/openqa/selenium/support/pagefactory/DefaultFieldDecorator.html">DefaultFieldDecorator</a>. A custom <span style="color: orange;">FieldDecorator</span> allows to use <span style="color: orange;">@FindBy</span>, <span style="color: orange;">@FindBys</span>, or <span style="color: orange;">@FindAll</span> annotations for custom HTML wrappers. A sample project providing implementation details and examples of custom elements is <a href="https://github.com/oraz/selenium">available here</a>. You can also catch the Selenium's infamous <a href="https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/StaleElementReferenceException.html">StaleElementReferenceException</a> in your custom <span style="color: orange;">FieldDecorator</span> and recreate the underlying <span style="color: orange;">WebElement</span> by the original locator. A framework user doesn't see then <span style="color: orange;">StaleElementReferenceException</span> and can call methods on <span style="color: orange;">WebElement</span> even when the referenced DOM element was updated in the meantime (removed from the DOM and added with a new content again). This idea with code snippet is <a href="http://brimllc.com/2011/01/extending-selenium-2-0-webdriver-to-support-ajax/">available here</a>.<br />
<br />
But ok, let me show the test class. In the test class, we want to test if a hint appears in the shopping cart when a child under 16 years travels without parents. Firts of all, we have to type the stations "from" and "to", click on a desired connection in the timetable and add a child on the next page which shows travel offers for the choosen connection.<br />
<pre class="brush:java">public class HintTravelerIT extends AbstractSeleniumTest {
@FlowOnPage(step = 1, desc = "Seach a connection from Bern to Zürich and click on the first 'Buy' button")
void flowTimetable(TimetablePage timetablePage) {
// Type from, to, date and time
timetablePage.typeFrom("Bern").typeTo("Zürich");
Date date = DateUtils.addDays(new Date(), 2);
timetablePage.typeDate(date);
timetablePage.typeTime(date);
// search for connections
timetablePage.search();
// click on the first 'Buy' button
TimetableTable table = timetablePage.getTimetableTable();
table.clickFirstBuyButton();
}
@FlowOnPage(step = 2, desc = "Add a child as traveler and test the hint in the shopping cart")
void flowOffers(OffersPage offersPage) {
// Add a child
DateFormat df = new SimpleDateFormat("dd.MM.yyyy", Locale.GERMAN);
String birthDay = df.format(DateUtils.addYears(new Date(), -10));
offersPage.addTraveler(0, "Max", "Mustermann", birthDay);
offersPage.saveTraveler();
// Get hints
List<String> hints = offersPage.getShoppingCart().getHints();
assertNotNull(hints);
assertTrue(hints.size() == 1);
assertEquals("A child can only travel under adult supervision", hints.get(0));
}
}
</pre>
<b><br /></b>
<b>The structure of a HTML Wrapper.</b><br />
<br />
I suggest to create an abstract base class for all HTML wrappers. Let's call it <span style="color: orange;">HtmlWrapper</span>. This class can provide some common methods, such as <span style="color: orange;">click</span>, <span style="color: orange;">clickAndWaitUntil</span>, <span style="color: orange;">findElement(s)</span>, <span style="color: orange;">getParentElement</span>, <span style="color: orange;">getAttribute</span>, <span style="color: orange;">isDisplayed</span>, ... For editable elements, you can create a class <span style="color: orange;">EditableWrapper</span> which inherits from the <span style="color: orange;">HtmlWrapper</span>. This class can provide some common methods for editable elements, such as <span style="color: orange;">clear</span> (clears the input), <span style="color: orange;">enter</span> (presses the enter key), <span style="color: orange;">isEnabled</span> (checks if the element is enabled), ... All editable elements should inherit from the <span style="color: orange;">EditableWrapper</span>. Futhermore, you can provide two interfaces <span style="color: orange;">EditableSingleValue</span> and <span style="color: orange;">EditableMultipleValue</span> for single and multi value elements respectively. The next diagram demonstrates the idea. It shows the class hierarchy for three basic HTML wrappes:<br />
<br />
<span style="color: orange;">Datepicker</span>. It inherits from the <span style="color: orange;">EditableWrapper</span> and implements the <span style="color: orange;">EditableSingleValue</span> interface.<br />
<span style="color: orange;">MultiSelect</span>. It inherits from the <span style="color: orange;">EditableWrapper</span> and implements the <span style="color: orange;">EditableMultiValue</span> interface.<br />
<span style="color: orange;">Message</span>. It extends directly the <span style="color: orange;">HtmlWrapper</span> because a message is not editable.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-bpHBXS8AYwU/VwDami6S88I/AAAAAAAAApM/936hT8vPgw0WNo9NaDDRYcZrwYVpPVwTQ/s1600/Wrapper.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="540" src="https://3.bp.blogspot.com/-bpHBXS8AYwU/VwDami6S88I/AAAAAAAAApM/936hT8vPgw0WNo9NaDDRYcZrwYVpPVwTQ/s640/Wrapper.png" width="640" /></a></div>
<br />
Do you want more implementation details for HTML wrappers? Details for an jQuery Datepicker can be found for example in <a href="http://seleniumcapsules.blogspot.de/2012/10/design-of-datepicker.html">this great article</a>. The MultiSelect is a wrapper around the famous <a href="https://select2.github.io/">Select2 widget</a>. I have implemented the wrapper in my project in the following way:
<br />
<pre class="brush:java">public class MultiSelect extends EditableWrapper implements EditableMultiValue<String> {
protected MultiSelect(WebElement element) {
super(element);
}
public static MultiSelect create(WebElement element) {
assertNotNull(element);
return new MultiSelect(element);
}
@Override
public void clear() {
JavascriptExecutor js = (JavascriptExecutor) getDriver();
js.executeScript("jQuery(arguments[0]).val(null).trigger('change')", element);
}
public void removeValue(String...value) {
if (value == null || value.length == 0) {
return;
}
JavascriptExecutor js = (JavascriptExecutor) getDriver();
Object selectedValues = js.executeScript("return jQuery(arguments[0]).val()", element);
String[] curValue = convertValues(selectedValues);
String[] newValue = ArrayUtils.removeElements(curValue, value);
if (newValue == null || newValue.length == 0) {
clear();
} else {
changeValue(newValue);
}
}
public void addValue(String...value) {
if (value == null || value.length == 0) {
return;
}
JavascriptExecutor js = (JavascriptExecutor) getDriver();
Object selectedValues = js.executeScript("return jQuery(arguments[0]).val()", element);
String[] curValue = convertValues(selectedValues);
String[] newValue = ArrayUtils.addAll(curValue, value);
changeValue(newValue);
}
@Override
public void setValue(String...value) {
clear();
if (value == null || value.length == 0) {
return;
}
changeValue(value);
}
@Override
public String[] getValue() {
JavascriptExecutor js = (JavascriptExecutor) getDriver();
Object values = js.executeScript("return jQuery(arguments[0]).val()", element);
return convertValues(values);
}
private void changeValue(String...value) {
Gson gson = new Gson();
String jsonArray = gson.toJson(value);
String jsCode = String.format("jQuery(arguments[0]).val(%s).trigger('change')", jsonArray);
JavascriptExecutor js = (JavascriptExecutor) getDriver();
js.executeScript(jsCode, element);
}
@SuppressWarnings("unchecked")
private String[] convertValues(Object values) {
if (values == null) {
return null;
}
if (values.getClass().isArray()) {
return (String[]) values;
} else if (values instanceof List) {
List<String> list = (List<String> ) values;
return list.toArray(new String[list.size()]);
} else {
throw new WebDriverException("Unsupported value for MultiSelect: " + values.getClass());
}
}
}
</pre>
And an example of Message implementation for the sake of completeness:
<br />
<pre class="brush:java">public class Message extends HtmlWrapper {
public enum Severity {
INFO("info"),
WARNING("warn"),
ERROR("error");
Severity(String severity) {
this.severity = severity;
}
private final String severity;
public String getSeverity() {
return severity;
}
}
protected Message(WebElement element) {
super(element);
}
public static Message create(WebElement element) {
assertNotNull(element);
return new Message(element);
}
public boolean isAnyMessageExist(Severity severity) {
List<WebElement> messages = findElements(
By.cssSelector(".ui-messages .ui-messages-" + severity.getSeverity()));
return messages.size() > 0;
}
public boolean isAnyMessageExist() {
for (Severity severity: Severity.values()) {
List<WebElement> messages = findElements(
By.cssSelector(".ui-messages .ui-messages-" + severity.getSeverity()));
if (messages.size() > 0) {
return true;
}
}
return false;
}
public List<String> getMessages(Severity severity) {
List<WebElement> messages = findElements(
By.cssSelector(".ui-messages .ui-messages-" + severity.getSeverity() + "-summary"));
if (messages.isEmpty()) {
return null;
}
List<String> text = new ArrayList<> ();
for (WebElement element: messages) {
text.add(element.getText());
}
return text;
}
}
</pre>
The Message wraps the <a href="http://www.primefaces.org/showcase/ui/message/messages.xhtml">Message component in PrimeFaces</a>.<br />
<br />
Conclusion: when you finished the writing of page objects and HTML wrappers, you can settle back and concentrate on the comfortable writing of Selenium tests. Feel free to share your thoughts.Oleg Varaksinhttp://www.blogger.com/profile/13872270134068047346noreply@blogger.com4tag:blogger.com,1999:blog-8492059842142356488.post-22091460245765894572016-03-20T16:21:00.003+01:002016-03-20T16:28:23.542+01:00Promises in AngularJS. Part II. $q service.I have already <a href="http://ovaraksin.blogspot.de/2015/09/promises-in-angularjs-part-i-basics.html">blogged about Promises in AngularJS 1.x</a>. This is the second part which describes the Angular's <span style="color: orange;">$q</span> service. The <span style="color: orange;">$q</span> service can be used in two different ways. The first way mimics the <a href="https://github.com/kriskowal/q">Q library</a> for creating and composing asynchronous promises in JavaScript. The second way mimics the ECMAScript 2015 (ES6) style. Let's begin with the first way. First of all, you have to create a <span style="color: orange;">deferred</span> object by <span style="color: orange;">$q.defer()</span>.
<br />
<pre class="brush:js">
var deferred = $q.defer();
</pre>
A <span style="color: orange;">deferred</span> object can be created within an asynchronous function. The function should return a promise object created from the <span style="color: orange;">deferred</span> object as follows:
<br />
<pre class="brush:js">
return deferred.promise;
</pre>
A promise is always in either one of three states:<br />
<ol>
<li><span style="color: orange;">Pending</span>: the result hasn't been computed yet</li>
<li><span style="color: orange;">Fulfilled</span>: the result was computed successfully</li>
<li><span style="color: orange;">Rejected</span>: a failure occurred during computation</li>
</ol>
When the asynchronous function finished the execution, it can invoke one of the two methods:
<br />
<pre class="brush:js">deferred.resolve(...)
deferred.reject(...)
</pre>
The first call <span style="color: orange;">deferred.resolve(...)</span> puts the promise into the fulfilled state. As result a <span style="color: orange;">success callback</span> will be invoked. The second call <span style="color: orange;">deferred.reject(...)</span> puts the promise into the rejected state. As result an <span style="color: orange;">error callback</span> will be invoked. It is also possible to invoke
<br />
<pre class="brush:js">
deferred.notify(...)
</pre>
during the function's execution to propogate some progress from the asynchronous function to an <span style="color: orange;">update callback</span>. All three callbacks can be registered on the promise as parameters of the function <span style="color: orange;">then</span>:
<br />
<pre class="brush:js">var promise = someAsynchronousFunction();
promise.then(function(value) {
// success
...
}, function(reason) {
// failure
...
}, function(update) {
// update
...
});
</pre>
Let's implement an example. We will take <span style="color: orange;">setTimeout()</span> as an asynchronous function. In the real application, you will probably use some other asynchronous services. In the <span style="color: orange;">setTimeout()</span>, we will generate a random number after 1 sek. If the number is less than 0.5, we will invoke <span style="color: orange;">deferred.resolve(random)</span>, otherwise <span style="color: orange;">deferred.reject(random)</span>. The entire logic is implemented in the controller <span style="color: orange;">PromiseController</span>.
<br />
<pre class="brush:js">var app = angular.module('app', []);
app.controller('PromiseController', PromiseController);
function PromiseController($q) {
var _self = this;
this.message = null;
var asyncFunction = function() {
var deferred = $q.defer();
setTimeout(function() {
var random = Math.random().toFixed(2);
if (random < 0.5) {
deferred.resolve(random);
} else {
deferred.reject(random);
}
}, 1000);
return deferred.promise;
}
this.invokeAsyncFunction = function() {
var promise = asyncFunction();
promise.then(function(message) {
_self.message = "Success: " + message;
}, function(message) {
_self.message = "Error: " + message;
});
}
}
</pre>
As you can see, the asynchronous function <span style="color: orange;">asyncFunction</span> is invoked in the controller's method <span style="color: orange;">invokeAsyncFunction</span>. The function <span style="color: orange;">asyncFunction</span> returns a promise. In the success case, the promise gets fulfilled and the first registered <span style="color: orange;">success callback</span> gets executed. In the error case, the promise gets rejected and the second registered <span style="color: orange;">error callback</span> gets executed. The <span style="color: orange;">invokeAsyncFunction</span> is bound to the onclick event on a button.
<br />
<pre class="brush:html"><!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta content="IE=edge" http-equiv="X-UA-Compatible" />
<script src="https://code.angularjs.org/1.4.8/angular.js"></script>
</head>
<body ng-app="app" ng-controller="PromiseController as ctrlPromise">
<div ng-bind="ctrlPromise.message"></div>
<p></p>
<button ng-click="ctrlPromise.invokeAsyncFunction()">
Invoke asynchronous function
</button>
<script src="controller.js"></script>
</body>
</html>
</pre>
The message in GUI looks like as follows (success case as example):<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-9Q56CYg-I8c/Vu68cQ7-ShI/AAAAAAAAAoA/tyUFbRnTRIULKBlijpAPnTJGidgqkkqrQ/s1600/asyncFunction.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://3.bp.blogspot.com/-9Q56CYg-I8c/Vu68cQ7-ShI/AAAAAAAAAoA/tyUFbRnTRIULKBlijpAPnTJGidgqkkqrQ/s1600/asyncFunction.png" /></a></div>
<br />
The Plunker of this example is <a href="http://plnkr.co/edit/HClkdYX3RxvjUwsu4aCn?p=preview">available here</a>. Here is another picture that visualize the relation between methods of the deferred object:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-PdI0T-rij5M/Vu68jXKoD6I/AAAAAAAAAoE/Mt84FFzUaO8xZY3BCIXPTZoY9mowak0Jw/s1600/promises.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://2.bp.blogspot.com/-PdI0T-rij5M/Vu68jXKoD6I/AAAAAAAAAoE/Mt84FFzUaO8xZY3BCIXPTZoY9mowak0Jw/s1600/promises.png" /></a></div>
<br />
As you can see, the asynchronous function doesn't return the <span style="color: orange;">deferred</span> object directly. The reason for that is obvious. If the <span style="color: orange;">deferred</span> object would be returned instead of <span style="color: orange;">deferred.promise</span>, the caller of the asynchronous function could be able to trigger callbacks by invoking <span style="color: orange;">deferred.resolve(...)</span>, <span style="color: orange;">deferred.reject(...)</span> or <span style="color: orange;">deferred.notify(...)</span>. For this reason these methods are protected from being invoking from outside by the caller.<br />
<br />
The example above can be rewritten in the ECMAScript 2015 (ES6) style (I mentioned this way at the beginning). A promise in ECMAScript 2015 can be created as an instance of <span style="color: orange;">Promise</span> object.
<br />
<pre class="brush:js">var promise = new Promise(function(resolve, reject) {
...
if(...) {
resolve(value); // success
} else {
reject(reason); // failure
}
});
</pre>
Our <span style="color: orange;">asyncFunction</span> function looks in this case as follows:
<br />
<pre class="brush:js">var asyncFunction = function() {
return $q(function(resolve, reject) {
setTimeout(function() {
var random = Math.random().toFixed(2);
if (random < 0.5) {
resolve(random);
} else {
reject(random);
}
}, 1000);
});
}
</pre>
The remaining code stays unchanged. Let's go on. The next question is, how can we produce a rejection in success or error callbacks? For instance, you check some condition in a callback and want to produce an error if the condition is not fulfilled. Sometimes, we also want to forward rejection in a chain of promises. That means, you catch an error via an error callback and you want to forward the error to the promise derived from the current promise. There are two ways to achieve this qoal. The first one consists in using the <span style="color: orange;">$q.reject(...)</span> like shown below.
<br />
<pre class="brush:js">var promise = someAsynchronousFunction();
promise.then(function(value) {
// success
...
if(someCondition) {
$q.reject("An error occurred!");
}
}, function(reason) {
// failure
...
}).catch(function(error) {
// do something in error case
...
});
</pre>
In our example, we will adjust the function <span style="color: orange;">invokeAsyncFunction</span> in order to check very small values (smaller than 0.1).
<br />
<pre class="brush:js">this.invokeAsyncFunction = function() {
var promise = asyncFunction();
promise.then(function(random) {
if (random < 0.1) {
return $q.reject("Very small random value!");
}
_self.message = "Success: " + random;
}, function(random) {
_self.message = "Error: " + random;
}).catch(function(error) {
_self.message = "Special error: " + error;
});
}
</pre>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-JKzLZ8u4Uhs/Vu6-T40cYnI/AAAAAAAAAoU/FhcO8x5GIVY9tc9DPCegURVVJXAWiNXKA/s1600/asyncFunction2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://3.bp.blogspot.com/-JKzLZ8u4Uhs/Vu6-T40cYnI/AAAAAAAAAoU/FhcO8x5GIVY9tc9DPCegURVVJXAWiNXKA/s1600/asyncFunction2.png" /></a></div>
<br />
A Plunker example is <a href="http://plnkr.co/edit/clcvSYttO3lU69K5V5tc?p=preview">available here</a>. Keep in mind the difference between <span style="color: orange;">deferred.reject(...)</span> and <span style="color: orange;">$q.reject(...)</span>. The call <span style="color: orange;">deferred.reject(...)</span> puts the corresponding promise into the rejected state. The call <span style="color: orange;">$q.reject(...)</span> creates a new promise which is already in the rejected state.<br />
<br />
The second way to produce a rejection in success or error callbacks consists in throwing an exception with <span style="color: orange;">throw new Error(...)</span>.<br />
<pre class="brush:js">this.invokeAsyncFunction = function() {
var promise = asyncFunction();
promise.then(function(random) {
if (random < 0.1) {
throw new Error("Very small random value!");
}
_self.message = "Success: " + random;
}, function(random) {
_self.message = "Error: " + random;
}).catch(function(error) {
_self.message = "Special error: " + error;
});
}
</pre>
AngularJS will catch the exception, create a promise in the rejected state and forward it to the next block in the chain of promises. In the example, the error will be forwarded to the catch block. One downside of this approach with <span style="color: orange;">throw new Error(...)</span> is that the error will be logged in the console. Picture from the Chrome Dev Tools:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-wGT85Xw1E30/Vu6-zYJZIiI/AAAAAAAAAoY/LuphDEayH_ICr2AqGlJ5c_r70Ip45DFbw/s1600/stackTrace.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://1.bp.blogspot.com/-wGT85Xw1E30/Vu6-zYJZIiI/AAAAAAAAAoY/LuphDEayH_ICr2AqGlJ5c_r70Ip45DFbw/s1600/stackTrace.png" /></a></div>
<br />
But well, it works as designed and probably it is even an advantage to see thrown errors in the console.
<br />
<br />
There is also an opposite method <span style="color: orange;">$q.when(...)</span> which returns an immediately resolved promise. The documentation says: <span style="color: orange;">$q.when(...)</span> "wraps an object that might be a value or a (3rd party) then-able promise into a <span style="color: orange;">$q</span> promise. This is useful when you are dealing with an object that might or might not be a promise, or if the promise comes from a source that can't be trusted." You can e.g. wrap an <a href="https://api.jquery.com/category/deferred-object/">jQuery Deferred Object</a> with <span style="color: orange;">$q.when(...)</span> or simple write
<br />
<pre class="brush:js">$q.when("Finished!").then(
function handleResolve(value) {
console.log("Resolved with value: ", value);
}
);
</pre>
and see <span style="color: orange;">Resolved with value: Finished!</span> in the console. The alias of <span style="color: orange;">$q.when(value)</span> is <span style="color: orange;">$q.resolve(value)</span>. This was introduced later in order to maintain naming consistency with ECMAScript 2015.<br />
<br />
Last but not least is the method <span style="color: orange;">$q.all(promises)</span> where <span style="color: orange;">promises</span> is an array of multiple promises. This call returns a single promise that is resolved when all promises in the given array gets resolved.
<br />
<pre class="brush:js">var promise1 = someAsynchronousFunction1();
var promise2 = someAsynchronousFunction2();
$q.all([promise1, promise2]).then(function(result) {
console.log("Promises " + result[0] + " and " + result[1] + " finished their work successfully");
});
</pre>
As you can see, the <span style="color: orange;">result</span> passed into the callback function is an array of two outcomes - the outcome of the first and the outcome of the second callback.Oleg Varaksinhttp://www.blogger.com/profile/13872270134068047346noreply@blogger.com2tag:blogger.com,1999:blog-8492059842142356488.post-33781119714914497712016-01-03T21:04:00.000+01:002016-01-03T21:09:04.949+01:00Installing Babel command line and playing with ES6If you would like to play with ECMAScript6, you can install <a href="http://babeljs.io/">Babel</a> CLI globally on your machine and run the <span style="color: orange;">babel-node</span> command. <span style="color: orange;">babel-node</span> is a version of the Node.js executable that understands ES6. It can be installed with the package manager NPM. Installation instructions are listed below.<br />
<br />
<b>1)</b> Install two Node.js modules <span style="color: orange;">babel</span> and <span style="color: orange;">babel-cli</span> one after another. Note: if you have some troubles during installation, update your Node.js and NPM to the latest stable versions.<br />
<br />
<span style="color: orange;">npm install --global babel</span><br />
<span style="color: orange;">npm install --global babel-cli</span><br />
<br />
<b>2)</b> Install a set of plugins for available ES6 (ES2015) features. Without these plugins you will get errors about unexpected token or similar. See <a href="http://babeljs.io/docs/plugins/preset-es2015/">http://babeljs.io/docs/plugins/preset-es2015/</a> for more details about supported ES6 features.<br />
<br />
<span style="color: orange;">npm install --global babel-preset-es2015</span><br />
<br />
<b>3a)</b> Start interactive REPL and type ES6 code. Note: globally installed modules on Windows are located under <span style="color: orange;">C:\Users\<Username>\AppData\Roaming\npm\node_modules</span><username>, so that we need to put a complete path to them.</username><br />
<br />
<username><span style="color: orange;">babel-node --presets C:\\Users\\Oleg\\AppData\\Roaming\\npm\\node_modules\\babel-preset-es2015</span><br /><span style="color: orange;">> let arr = [1,2,3]</span><br /><span style="color: orange;">> arr.map(x => x * x)</span><br />Output: <span style="color: orange;">[1,4,9]</span></username><br />
<br />
<username><b>3b)</b> Alternative, you can place some ES6 code into a file, e.g. <span style="color: orange;">testes6.js</span>, and let it run.</username><br />
<br />
<username><span style="color: orange;">babel-node --presets C:\\Users\\Oleg\\AppData\\Roaming\\npm\\node_modules\\babel-preset-es2015 testes6.js</span><br />Output: <span style="color: orange;">[1,4,9]</span></username><br />
<br />
<username>In the example, <span style="color: orange;">babel-node</span> is executed in the same directory where the file <span style="color: orange;">testes6.js</span> is located.</username><br />
<br />
<username>Enjoy.</username>Oleg Varaksinhttp://www.blogger.com/profile/13872270134068047346noreply@blogger.com0tag:blogger.com,1999:blog-8492059842142356488.post-45998117588423273102015-12-30T18:35:00.005+01:002015-12-30T18:41:33.400+01:00The best way for sharing data between controllers in AngularJS 1.xYou may know the situation in AngularJS 1.x when multiple independent controllers need to share some data. E.g. one controller adds some data that should be available in the other controllers in the same view. So far as I know there are three possibilities:<br />
<ul>
<li>Using <span style="color: orange;">$scope</span>, e.g. <span style="color: orange;">$scope</span> of a common parent controller or <span style="color: orange;">$rootScope</span></li>
<li>Using publish-subscribe design pattern via <span style="color: orange;">$emit</span> / <span style="color: orange;">$broadcast</span> (fire events) and <span style="color: orange;">$on</span> (listen for events)</li>
<li>Using services which can be injected in multiple controllers. </li>
</ul>
The first possibility to share data via <span style="color: orange;">$scope</span> is a bad idea. If you share data via scopes, you have to know controllers' parent-child relationship. That means, your controllers are tightly coupled and the refactoring is hard to master. Some AngularJS examples save the data on the <span style="color: orange;">$rootScope</span>, but the pollution of <span style="color: orange;">$rootScope</span> is not recommended. Keep the <span style="color: orange;">$rootScope</span> as small as possible. The event based possibility to share data via <span style="color: orange;">$emit</span>, <span style="color: orange;">$broadcast</span> and <span style="color: orange;">$on</span> is a better approach in comparison to scope based one. The controllers are loosely coupled. But there is a disadvantage as well - the performance. The performance is ok for a small application, but for a large application with hundreds of <span style="color: orange;">$on</span> listeners, the AngularJS has to introspect all scopes in order to find the <span style="color: orange;">$on</span> listeners that fit to the corresponsing <span style="color: orange;">$emit</span> / <span style="color: orange;">$broadcast</span>. From the architecture point there is a shortcoming as well - we still need scopes to register <span style="color: orange;">$emit</span>, <span style="color: orange;">$broadcast</span> and <span style="color: orange;">$on</span>. Some people also say - communication details should be hidden for the same reason we keep <span style="color: orange;">$http</span> hidden behind a service layer. There are <a href="http://www.technofattie.com/2014/03/21/five-guidelines-for-avoiding-scope-soup-in-angular.html">5 guidelines for avoiding scope soup in AngularJS</a>. The last 5. rule is called <span style="color: orange;">Don't Use Scope To Pass Data Around</span>. It advices against using scopes directly and against event based approach. Last but not least - think about the upcomming AngularJS 2. It doesn't have scopes!<br />
<br />
In my opinion, the preferred way for sharing data between controllers in AngularJS 1.x is the third possibility. We can use services. A service can keep data or acts as event emitter (example is shown below). Any service can be injected into controllers, so that conrollers still don't know from each other and thus are loosely coupled. I will refactor and extend <a href="https://daveceddia.com/sharing-data-between-controllers-best-practice-use-a-service/">one example from this blog post</a>. The author of this blog post implemented two controllers for two panes. In the left pane we can input some text and add it as an item to a list in the right pane. The list itself is placed in a service (service encapsulates the data). This is probably a good idea when you have different views or controllers in conditional <span style="color: orange;">ng-if</span>. But if controllers exist in the same view and show their data at the same time, the list should reside in the controller for the right pane and not in the service. The list belongs to the second controller. This is my opinion, so I will move the list into the controller and also add a third "message controller" which is responsible for messages when user adds items to the list or removes them from the list. We thus have three controllers and one service. The idea is to apply the listener pattern (also known as observer) to the service. The service acts as event emitter. Every controller can fire an ADD or REMOVE operation and register a listener function to be notified when the operation is done. The added / removed item acts as data passed along with operation into all registered listeners for the given operation. <a href="http://plnkr.co/edit/sYraTzhscg7wIZ0S1O9v?p=preview">The live example</a> is implemented on Plunker.<br />
<br />
The first picture shows the adding process (click on the button <span style="color: orange;">Add To List</span>) with a message about the successfully added item.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-PdFuu0l0I8k/VoQUY8b2EnI/AAAAAAAAAm8/nY9LRXZM-rc/s1600/addItem.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-PdFuu0l0I8k/VoQUY8b2EnI/AAAAAAAAAm8/nY9LRXZM-rc/s1600/addItem.png" /></a></div>
<br />
The second picture shows the removing process (click on a link with <span style="color: orange;">x</span> symbol) with a message about the successfully removed item.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-EAENoHgT6B4/VoQUerG5t-I/AAAAAAAAAnE/cvasbiMX_gM/s1600/removeItem.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-EAENoHgT6B4/VoQUerG5t-I/AAAAAAAAAnE/cvasbiMX_gM/s1600/removeItem.png" /></a></div>
<br />
The HTML part looks as follows:
<br />
<pre class="brush:html"><!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta content="IE=edge" http-equiv="X-UA-Compatible" />
<script src="https://code.angularjs.org/1.4.8/angular.js"></script>
</head>
<body ng-app="app">
<div ng-controller="MessageController as ctrlMessage" style="margin-bottom:20px;">
<span ng-bind-html="ctrlMessage.message"></span>
</div>
<div ng-controller="PaneOneController as ctrlPaneOne">
<input ng-model="ctrlPaneOne.item">
<button ng-click="ctrlPaneOne.addItem(ctrlPaneOne.item)">Add To List</button>
</div>
<div ng-controller="PaneTwoController as ctrlPaneTwo" style="float:right; width:50%; margin-top:-20px;">
<ul style="margin-top:0">
<li ng-repeat="item in ctrlPaneTwo.list track by $index">
{{item}}
<a href style="margin-left:5px;" title="Remove" ng-click="ctrlPaneTwo.removeItem($index)">x</a>
</li>
</ul>
</div>
<script src="controller.js"></script>
<script src="service.js"></script>
</body>
</html>
</pre>
As you can see, there are three independent HTML div elements with <span style="color: orange;">ng-controller</span> directive. The <span style="color: orange;">MessageController</span> shows a message above. The <span style="color: orange;">PaneOneController</span> keeps an input value and the function <span style="color: orange;">addItem()</span>. The <span style="color: orange;">PaneTwoController</span> keeps a list with all items and the function <span style="color: orange;">removeItem()</span>. The controllers look as follows in details:
<br />
<pre class="brush:js">(function() {
var app = angular.module('app', []);
app.controller('PaneOneController', PaneOneController);
app.controller('PaneTwoController', PaneTwoController);
app.controller('MessageController', MessageController);
/* first controller */
function PaneOneController(EventEmitterListService) {
var _self = this;
this.item = null;
this.addItem = function(item) {
EventEmitterListService.emitAddItem(item);
_self.item = null;
}
}
/* second controller */
function PaneTwoController($scope, EventEmitterListService) {
var _self = this;
this.list = [];
this.removeItem = function(index) {
var removed = _self.list.splice(index, 1);
EventEmitterListService.emitRemoveItem(removed[0]);
}
EventEmitterListService.onAddItem('PaneTwo', function(item) {
_self.list.push(item);
});
$scope.$on("$destroy", function() {
EventEmitterListService.clear('PaneTwo');
});
}
/* third controller */
function MessageController($scope, $sce, EventEmitterListService) {
var _self = this;
this.message = null;
EventEmitterListService.onAddItem('Message', function(item) {
_self.message = $sce.trustAsHtml("<strong>" + item + "</strong> has been added successfully");
});
EventEmitterListService.onRemoveItem('Message', function(item) {
_self.message = $sce.trustAsHtml("<strong>" + item + "</strong> has been removed successfully");
});
$scope.$on("$destroy", function() {
EventEmitterListService.clear('Message');
});
}
})();
</pre>
All three controllers communicate with a service called <span style="color: orange;">EventEmitterListService</span>. The service exposes three methods:<br />
<ul>
<li><span style="color: orange;">emitAddItem</span> - notifies listeners that are interested in adding an item to the list. The item is passed as parameter.</li>
<li><span style="color: orange;">emitRemoveItem</span> - notifies listeners that are interested in removing an item from the list. The item is passed as parameter.</li>
<li><span style="color: orange;">onAddItem</span> - registers a listener function that is interested in adding an item to the list. The listener is passed as parameter.</li>
<li><span style="color: orange;">onRemoveItem</span> - registers a listener function that is interested in removing an item from the list. The listener is passed as parameter.</li>
<li><span style="color: orange;">clear</span> - removes all registered listeners which belong to the specified controller. The controller is identified by the scope parameter (simple unique string).</li>
</ul>
The <span style="color: orange;">clear</span> method is important when the <span style="color: orange;">$scope</span> gets destroyed (e.g. when the DOM associated with the <span style="color: orange;">$scope</span> gets removed due to <span style="color: orange;">ng-if</span> or view switching). This method should be invoked on <span style="color: orange;">$destroy</span> event - see code snippets with <span style="color: orange;">$scope.$on("$destroy", function() {...})</span>. The full code of the service is listed below:
<br />
<pre class="brush:js">(function() {
var app = angular.module('app');
app.factory('EventEmitterListService', EventEmitterListService);
function EventEmitterListService() {
// Format of any object in the array:
// {scope: ..., add: [...], remove: [...]}
// "scope": some identifier, e.g. it can be the part of controller's name
// "add": array of listeners for the given scope to be notified when an item is added
// "remove": array of listeners for the given scope to be notified when an item is removed
var listeners = [];
function emitAddItem(item) {
emitAction('add', item);
}
function onAddItem(scope, listener) {
onAction('add', scope, listener);
}
function emitRemoveItem(item) {
emitAction('remove', item);
}
function onRemoveItem(scope, listener) {
onAction('remove', scope, listener);
}
function clear(scope) {
var index = findIndex(scope);
if (index > -1) {
listeners.splice(index, 1);
}
}
function emitAction(action, item) {
listeners.forEach(function(obj) {
obj[action].forEach(function(listener) {
listener(item);
});
});
}
function onAction(action, scope, listener) {
var index = findIndex(scope);
if (index > -1) {
listeners[index][action].push(listener);
} else {
var obj = {
'scope': scope,
'add': action == 'add' ? [listener] : [],
'remove': action == 'remove' ? [listener] : []
}
listeners.push(obj);
}
}
function findIndex(scope) {
var index = -1;
for (var i = 0; i < listeners.length; i++) {
if (listeners[i].scope == scope) {
index = i;
break;
}
}
return index;
}
var service = {
emitAddItem: emitAddItem,
onAddItem: onAddItem,
emitRemoveItem: emitRemoveItem,
onRemoveItem: onRemoveItem,
clear: clear
};
return service;
}
})();
</pre>
That's all. Happy New Year!Oleg Varaksinhttp://www.blogger.com/profile/13872270134068047346noreply@blogger.com2tag:blogger.com,1999:blog-8492059842142356488.post-85137848109616954832015-12-23T21:40:00.000+01:002015-12-23T21:46:41.144+01:00Mock responses to HTTP calls with network traffic simulation by using ngMockE2EThe AngularJS' module <a href="https://docs.angularjs.org/api/ngMockE2E">ngMockE2E</a> allows to fake HTTP backend implementation for unit testing and to respond with static or dynamic responses via the <span style="color: orange;">when</span> API and its shortcuts (<span style="color: orange;">whenGET</span>, <span style="color: orange;">whenPOST</span>, etc). In this post, I will only demonstrate how to respond to any HTTP calls by mocking the responses. We will also see how the network load can be simulated. Such behavior gives a feeling of real remote calls. The implemented <a href="http://plnkr.co/edit/B3ADvxLtNFlZt2RAu836?p=preview">example is available on Plunker</a>. It shows a small CRUD application to manage imaginary persons. There are four buttons for sending AJAX requests in a REST like manner. When a request is sent, you can see the text <span style="color: orange;">Loading...</span> which disappears after 2 seconds when the response "is arrived". In fact, no request is sent of course. This is just a simulation with the AngularJS' module <span style="color: orange;">ngMockE2E</span>. The network load takes exactly 2 seconds but you can set another delay value if you want<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-DFmuZWNbRdc/Vnr_UgCWP2I/AAAAAAAAAls/wSXtV8TMXqQ/s1600/0-loading.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-DFmuZWNbRdc/Vnr_UgCWP2I/AAAAAAAAAls/wSXtV8TMXqQ/s1600/0-loading.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
The first button sends a GET request to <span style="color: orange;">/persons</span> to receives all available persons. If you click on this button, you will see three persons received from the imaginary backend.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-6Q0s6QVZvHE/Vnr_eGzjdiI/AAAAAAAAAl4/90wQVSEPgCQ/s1600/1-get-persons.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-6Q0s6QVZvHE/Vnr_eGzjdiI/AAAAAAAAAl4/90wQVSEPgCQ/s1600/1-get-persons.png" /></a></div>
<br />
The second button sends a GET request to <span style="color: orange;">/person/:id</span> to receives one person by its ID. The ID is appended to the URI part <span style="color: orange;">/person/</span>. If you type e.g. 2 and click on this button, you should see the following person<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-uIwzQo07NwU/VnsAFVBuP1I/AAAAAAAAAl8/lLuIhJyvWh0/s1600/2-get-person.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-uIwzQo07NwU/VnsAFVBuP1I/AAAAAAAAAl8/lLuIhJyvWh0/s1600/2-get-person.png" /></a></div>
<br />
There is also a proper validation. If you type e.g. 4, no person will be found because no person with the ID 4 exists in "the backend".<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/--L4GxWm1mLM/VnsAT8ujm6I/AAAAAAAAAmE/E3VArgRWbxs/s1600/3-get-person-not-found.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/--L4GxWm1mLM/VnsAT8ujm6I/AAAAAAAAAmE/E3VArgRWbxs/s1600/3-get-person-not-found.png" /></a></div>
<br />
If you type some wrong ID which is not a numeric value, an error message will be shown as well.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-a1zlFxnSQkw/VnsAfQ4sKCI/AAAAAAAAAmM/4-JSBuXzetw/s1600/4-get-person-unexpected.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-a1zlFxnSQkw/VnsAfQ4sKCI/AAAAAAAAAmM/4-JSBuXzetw/s1600/4-get-person-unexpected.png" /></a></div>
<br />
The third button sends a POST request to <span style="color: orange;">/person</span> to create a new person or update existing one. The input fields <span style="color: orange;">name</span> and <span style="color: orange;">birthday</span> are required. You can type a name and birthday for a new person, sends the POST request and see the created person recived from "the backend".<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-co9pma1IDk8/VnsA2E-qrVI/AAAAAAAAAmU/04A56AwZeI4/s1600/5-post-person.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-co9pma1IDk8/VnsA2E-qrVI/AAAAAAAAAmU/04A56AwZeI4/s1600/5-post-person.png" /></a></div>
<br />
Now, if you sends a GET request to <span style="color: orange;">/persons</span> (the first button), you should see the created person in the list of all persons.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-PaR7M0R6iis/VnsBBLwGVqI/AAAAAAAAAmc/iVpBGO3fmBs/s1600/6-get-persons.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-PaR7M0R6iis/VnsBBLwGVqI/AAAAAAAAAmc/iVpBGO3fmBs/s1600/6-get-persons.png" /></a></div>
<br />
The last button deletes a person by sending the DELETE request to <span style="color: orange;">/person/:id</span>. The deleted person is shown above the buttons.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-Jt391IA09M8/VnsBSRWBcWI/AAAAAAAAAmk/vhutqsE0yIE/s1600/7-delete-person.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-Jt391IA09M8/VnsBSRWBcWI/AAAAAAAAAmk/vhutqsE0yIE/s1600/7-delete-person.png" /></a></div>
<br />
Click on the first button again to ensure that the person was deleted and doesn't exist more.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-nSqT86jmv5g/VnsBcRIAbaI/AAAAAAAAAms/lNU9JY83GsA/s1600/8-get-persons.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-nSqT86jmv5g/VnsBcRIAbaI/AAAAAAAAAms/lNU9JY83GsA/s1600/8-get-persons.png" /></a></div>
<br />
Let's show the code. First of all you have to include the file <span style="color: orange;">angular-mocks.js</span> after the file <span style="color: orange;">angular.js</span> in order to overwrite the original <span style="color: orange;">$httpBackend</span> functionality.
<br />
<pre class="brush:html"><script src="https://code.angularjs.org/1.4.8/angular.js"></script>
<script src="https://code.angularjs.org/1.4.8/angular-mocks.js"></script>
</pre>
What is <span style="color: orange;">$httpBackend</span>? In AngularJS, we normally use a high level <span style="color: orange;">$http</span> or <span style="color: orange;">$resource</span> service for HTTP calls. These services use for their part a low level service called <a href="https://docs.angularjs.org/api/ngMockE2E/service/$httpBackend">$httpBackend</a>. The <span style="color: orange;">$httpBackend</span> has useful methods to create new backend definitions for various request types. There is a method <span style="color: orange;">when(method, url, [data], [headers], [keys])</span> and many shortcut methods such as<br />
<ul>
<li>whenGET(url, [headers], [keys])</li>
<li>whenHEAD(url, [headers], [keys])</li>
<li>whenDELETE(url, [headers], [keys])</li>
<li>whenPOST(url, [data], [headers], [keys])</li>
<li>whenPUT(url, [data], [headers], [keys])</li>
<li>...</li>
</ul>
The most interesting parameter is the <span style="color: orange;">url</span>. This can be a String like <span style="color: orange;">/persons</span>, a regular expression like <span style="color: orange;">/^\/person\/([0-9]+)$/</span> for <span style="color: orange;">/person/:id</span> or a function that receives the <span style="color: orange;">url</span> and returns true if the <span style="color: orange;">url</span> matches the current definition. These methods return an object with <span style="color: orange;">respond</span> and <span style="color: orange;">passThrough</span> functions that control how a matched request is handled. The <span style="color: orange;">passThrough</span> is useful when the backend REST API is ready to use and you want to pass mocked request to the real HTTP call. In this example, we only use the <span style="color: orange;">respond</span>. The <span style="color: orange;">respond</span> can take the object to be returned, e.g. <span style="color: orange;">$httpBackend.whenGET('/persons').respond(persons)</span> or a function <span style="color: orange;">function(method, url, data, headers, params)</span> which returns an array containing response status (number), response data (string), response headers (object), and the text for the status (string). The file <span style="color: orange;">app.js</span> demonstrates how to use the <span style="color: orange;">$httpBackend</span>.
<br />
<pre class="brush:js">(function() {
var app = angular.module('app', ["ngMockE2E"]);
app.run(HttpBackendMocker);
// original list of persons
var persons = [
{id: 1, name: 'Max Mustermann', birthdate: '01.01.1970'},
{id: 2, name: 'Sara Smidth', birthdate: '31.12.1982'},
{id: 3, name: 'James Bond', birthdate: '05.05.1960'}
];
// Reg. expression for /person/:id
var regexPersonId = /^\/person\/([0-9]+)$/;
function HttpBackendMocker($httpBackend) {
// GET /persons
$httpBackend.whenGET('/persons').respond(persons);
// GET /person/:id
$httpBackend.whenGET(regexPersonId).respond(function(method, url) {
var id = url.match(regexPersonId)[1];
var foundPerson = findPerson(id);
return foundPerson ? [200, foundPerson] : [404, 'Person not found'];
});
// POST /person
$httpBackend.whenPOST('/person').respond(function(method, url, data) {
var newPerson = angular.fromJson(data);
// does the person already exist?
var existingPerson = findPerson(newPerson.id);
if (existingPerson) {
// update existing person
angular.extend(existingPerson, newPerson);
return [200, existingPerson];
} else {
// create a new person
newPerson.id = persons.length > 0 ? persons[persons.length - 1].id + 1 : 1;
persons.push(newPerson);
return [200, newPerson];
}
});
// DELETE: /person/:id
$httpBackend.whenDELETE(regexPersonId).respond(function(method, url) {
var id = url.match(regexPersonId)[1];
var foundPerson = findPerson(id);
if (foundPerson) {
persons.splice(foundPerson.id - 1, 1);
// re-set ids
for (var i = 0; i < persons.length; i++) {
persons[i].id = i + 1;
}
}
return foundPerson ? [200, foundPerson] : [404, 'Person not found'];
});
// helper function to find a person by id
function findPerson(id) {
var foundPerson = null;
for (var i = 0; i < persons.length; i++) {
var person = persons[i];
if (person.id == id) {
foundPerson = person;
break;
}
}
return foundPerson;
}
}
})();
</pre>
Now we need a custom service that encapsulates the <span style="color: orange;">$http</span> service. The service will get the name <span style="color: orange;">DataService</span>. It is placed in the file <span style="color: orange;">service.js</span>.
<br />
<pre class="brush:js">(function() {
var app = angular.module('app');
app.factory('DataService', DataService);
function DataService($http) {
var service = {
getPersons: getPersons,
getPerson: getPerson,
addPerson: addPerson,
removePerson: removePerson
};
return service;
function getPersons() {
return $http.get('/persons').then(
function(response) {
return response.data;
},
function(error) {
// do something in failure case
}
);
}
function getPerson(id) {
return $http.get('/person/' + id).then(
function(response) {
return response.data;
},
function(error) {
if (error.status && error.status === 404) {
return error.data;
} else {
return "Unexpected request";
}
}
);
}
function addPerson(person) {
return $http.post('/person', person).then(
function(response) {
return response.data;
},
function(error) {
// do something in failure case
}
);
}
function removePerson(id) {
return $http.delete('/person/' + id).then(
function(response) {
return response.data;
},
function(error) {
if (error.status && error.status === 404) {
return error.data;
} else {
return "Unexpected request";
}
}
);
}
}
})();
</pre>
The service <span style="color: orange;">DataService</span> is invoked by a controller which I named <span style="color: orange;">DataController</span> and placed in the <span style="color: orange;">controller.js</span>.
<br />
<pre class="brush:js">(function() {
var app = angular.module('app');
app.controller('DataController', DataController);
function DataController($scope, DataService) {
var _self = this;
this.persons = [];
this.personId = null;
this.person = {};
this.message = null;
this.loading = false;
this.getPersons = function() {
init();
DataService.getPersons().then(function(data) {
_self.persons = data;
_self.loading = false;
})
}
this.getPerson = function(id) {
// check required input
if ($scope.form.id4get.$error.required) {
_self.message = "Please add person's id";
return;
}
init();
DataService.getPerson(id).then(function(data) {
if (typeof data === "string") {
// error
_self.message = data;
_self.persons = null;
} else {
_self.persons = [data];
}
_self.loading = false;
})
}
this.addPerson = function(person) {
// check required input
if ($scope.form.name.$error.required) {
_self.message = "Please add person's name";
return;
}
if ($scope.form.birthdate.$error.required) {
_self.message = "Please add person's birthdate";
return;
}
init();
DataService.addPerson(person).then(function(data) {
_self.persons = [data];
_self.loading = false;
})
}
this.removePerson = function(id) {
// check required input
if ($scope.form.id4delete.$error.required) {
_self.message = "Please add person's id";
return;
}
init();
DataService.removePerson(id).then(function(data) {
if (typeof data === "string") {
// error
_self.message = data;
_self.persons = null;
} else {
_self.persons = [data];
}
_self.loading = false;
})
}
// helper function to reset internal state
var init = function() {
_self.persons = [];
_self.message = null;
_self.loading = true;
}
}
})();
</pre>
Now we can use the controller in the view - the file <span style="color: orange;">index.html</span>
<br />
<pre class="brush:html"><!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta content="IE=edge" http-equiv="X-UA-Compatible" />
<script src="https://code.angularjs.org/1.4.8/angular.js"></script>
<script src="https://code.angularjs.org/1.4.8/angular-mocks.js"></script>
</head>
<body ng-app="app">
<div ng-controller="DataController as ctrl" ng-cloak>
<ul style="padding-left:0; list-style:none;">
<li ng-repeat="person in ctrl.persons">
{{person.id}} - {{person.name}} - {{person.birthdate}}
</li>
</ul>
<div style="margin-bottom:15px;" ng-show="ctrl.loading">Loading ...</div>
<div style="color:red; margin-bottom:15px;" ng-show="ctrl.message">{{ctrl.message}}</div>
<form name="form" novalidate>
<button ng-click="ctrl.getPersons()">GET /persons</button>
<p></p>
<button ng-click="ctrl.getPerson(ctrl.personId)">GET /person/:id</button>
<input ng-model="ctrl.personId" name="id4get" required placeholder="id" />
<p></p>
<button ng-click="ctrl.addPerson(ctrl.person)">POST /person</button>
<input ng-model="ctrl.person.name" name="name" required placeholder="name" />
<input ng-model="ctrl.person.birthdate" name="birthdate" required placeholder="birthdate" />
<p></p>
<button ng-click="ctrl.removePerson(ctrl.personId)">DELETE /person/:id</button>
<input ng-model="ctrl.personId" name="id4delete" required placeholder="id" />
</form>
</div>
<script src="app.js"></script>
<script src="config.js"></script>
<script src="service.js"></script>
<script src="controller.js"></script>
</body>
</html>
</pre>
The current implementation has one shortcoming. The text <span style="color: orange;">Loading ...</span> is not shown at all because the response is delivered very quickly, so that user doesn't see it. It would be nice to delay HTTP calls in order to simulate the network load. For this purpose we can use the <span style="color: orange;">$provide</span> service and register a service decorator for the <span style="color: orange;">$httpBackend</span>. The service decorator acts as proxy. If you look into the source code of the <span style="color: orange;">$httpBackend</span>, you can see that the <span style="color: orange;">$httpBackend</span> is created by the constructor <span style="color: orange;">function(method, url, data, callback, headers, timeout, withCredentials)</span>. The four parameter <span style="color: orange;">callback</span> is responsible for the response. We have to provide our own implementation which I named <span style="color: orange;">delayedCallback</span>. The <span style="color: orange;">delayedCallback</span> function invokes the original callback with a delay (here 2 seconds) by means of <span style="color: orange;">setTimeout()</span>. We delegate the proxy call to the <span style="color: orange;">$httpBackend</span> instantiation, but with the new delayed callback. The injected <span style="color: orange;">$delegate</span> object points exactly to the <span style="color: orange;">$httpBackend</span>. The full code is shown below.
<br />
<pre class="brush:js">(function() {
var app = angular.module('app');
app.config(HttpBackendConfigurator);
function HttpBackendConfigurator($provide) {
$provide.decorator('$httpBackend', HttpBackendDecorator);
function HttpBackendDecorator($delegate) {
var proxy = function(method, url, data, callback, headers, timeout, withCredentials) {
// create proxy for callback parameter
var delayedCallback = function() {
// simulate network load with 2 sec. delay
var delay = 2000;
// Invoke callback with delaying
setTimeout((function() {
callback.apply(this, arguments[0]);
}.bind(this, arguments)), delay);
};
// delegate to the original $httpBackend call, but with the new delayed callback
$delegate(method, url, data, delayedCallback, headers, timeout, withCredentials);
};
// the proxy object should get all properties from the original $httpBackend object
angular.extend(proxy, $delegate);
// return proxy object
return proxy;
}
}
})();
</pre>
Oleg Varaksinhttp://www.blogger.com/profile/13872270134068047346noreply@blogger.com0tag:blogger.com,1999:blog-8492059842142356488.post-48295149465293524372015-10-27T10:24:00.001+01:002015-10-27T10:24:34.531+01:00PrimeFaces Extensions 4.0.0 releasedDear Community,<br />
<br />
A new 4.0.0 version of <a href="http://primefaces-extensions.github.io/">PrimeFaces Extensions</a> has been released. Artefacts are available in the <a href="http://search.maven.org/#search%7Cga%7C1%7Cprimefaces-extensions">Maven central</a>.<br />
<br />
Release notes there are as usually on the <a href="https://github.com/primefaces-extensions/primefaces-extensions.github.com/wiki/Release-Notes">project's wiki page</a>.<br />
<br />
This version is fully compatible with the latest PrimeFaces 5.3.<br />
<br />
Enjoy.Oleg Varaksinhttp://www.blogger.com/profile/13872270134068047346noreply@blogger.com3tag:blogger.com,1999:blog-8492059842142356488.post-23702406831365583452015-09-21T00:29:00.002+02:002015-09-26T23:37:33.685+02:00Promises in AngularJS. Part I. Basics.There are many blog posts about Promises in general and Promises in AngularJS in particular. Promises are a part of the ES6 (EcmaScript 6) specification, so it is worth to learn them. In this blog post, I will try to summarize the most important info about Promises in a simple and clear way. The necessary code snippets will be provided too. The first part is about basics.<br />
<br />
What is a <span style="color: orange;">Promise</span>? Promise is a solution to avoid so-called <span style="color: orange;">"Pyramid of Doom"</span>. If you work with asynchronous operations (HTTP calls, file system operations, etc.), you know the situation where you have callbacks nested inside of another callbacks which are nested again inside of callbacks and so on. An example:
<br />
<pre class="brush:js">asyncOperationOne('first data', function(firstResult) {
asyncOperationTwo('second data', function(secondResult) {
asyncOperationThree('third data', function(thirdResult) {
asyncOperationFour('fourth data', function(fourthResult) {
doSomething();
});
});
});
});
</pre>
Every asynchronous operation invokes a callback function when the operation is completely done. In case of AngularJS and the <span style="color: orange;">$http</span> service the "Pyramid of Doom" could look as follows:
<br />
<pre class="brush:js">var result = [];
$http.get('/api/data/first.json').success(function(data) {
result.push(data);
$http.get('/api/data/second.json').success(function(data) {
result.push(data);
$http.get('/api/data/third.json').success(function(data) {
result.push(data);
$scope.result = result;
});
});
});
</pre>
We didn't show yet the error handling. Now imagine how it looks like with error handling. Terrible and not readable. Promises help to synchronize multiple asynchronous functions and avoid Javascript callback hell. The official concept of Promises is described in the <a href="https://promisesaplus.com/">Promises/A+ specification</a>. With promises, an asynchronous call returns a special object called <span style="color: orange;">Promise</span>. The calling code can then wait until that promise is fulfilled before executing the next step. To do so, the promise has a method named <span style="color: orange;">then</span>, which accepts two functions - success and error function. The success function will be invoked when the promise has been fulfilled. The error function will be invoked when the promise has been rejected. An example of <span style="color: orange;">$http</span> service based on promises:
<br />
<pre class="brush:js">$http.get('/api/data.json').then(
function(response) {
...
},
function(error) {
...
}
);
</pre>
We can say, a promise represents the future result of an asynchronous operation. The real power from promises is the chaining. You can chain promises. The <span style="color: orange;">then</span> function returns a new promise, known as derived promise. The return value of some promise's callback is passed as parameter to the callback of the next promise. In this way, you can access previous promise results in a <span style="color: orange;">.then()</span> chain. An error is passed too, so that you can define just one error callback at the end of chain and handle all errors there. Here is an example of promise chaining:
<br />
<pre class="brush:js">$http.get('/api/data.json').then(
function(response) {
return doSomething1(response);
})
.then(function(response) {
return doSomething2(response);
})
.then(function(response) {
return doSomething3(response);
}, function(error) {
console.log('An error occurred!', error);
}
);
</pre>
If you return some value from the derived promise as shown above, the derived promise will be resolved immediately. A derived promise can be deferred as well. That means, the resolution / rejection of the derived promise can be deferred until the previous promise has been resolved / rejected. This is done by returning a promise from the success or error callback. The AngularJS' <span style="color: orange;">$http</span> service returns a promise, so that we can rewrite the shown above "Pyramid of Doom" with <span style="color: orange;">$http</span> as
<br />
<pre class="brush:js">$http.get('/api/data/first.json').then(
function(response) {
// response here comes from the GET to /api/data/first.json
result.push(response.data);
return $http.get('/api/data/second.json');
})
.then(function(response) {
// response here comes from the GET to /api/data/second.json
result.push(response.data);
return $http.get('/api/data/third.json');
})
.then(function(response) {
// response here comes from the GET to /api/data/third.json
result.push(response.data);
$scope.result = result;
}, function(error) {
console.log('An error occurred!', error);
}
);
</pre>
What happens now when a HTTP call in the promise chain fails? In this case, success callbacks in every subsequent promise in the chain will be skipped (not invoked). The next error callback in the promise chain however will be invoked. Therefore, the error callback is indispensable. An example:
<br />
<pre class="brush:js">$http.get('/api/data/wrong_or_failed_url.json').then(
function(response) {
// this function is not invoked
return $http.get('/api/data/second.json');
})
.then(function(response) {
// this function is not invoked
return $http.get('/api/data/third.json');
})
.then(function(response) {
// this function is not invoked
$scope.result = response.data;
}, function(error) {
// error callback gets invoked
console.log('An error occurred!', error);
}
);
</pre>
Instead of error callback you can also use an equivalent - promise's function <span style="color: orange;">catch</span>. The construct <span style="color: orange;">promise.catch(errorCallback)</span> is a shorthand for <span style="color: orange;">promise.then(null, errorCallback)</span>.<br />
<br />
Be aware that either the success or the error callback will be invoked, but never both. What to do if you need to ensure a specific function always executes regardless of the result of the promise? You can do this by registering that function on the promise using the <span style="color: orange;">finally()</span> method. In this method, you can reset some state or clear some resources. An example:
<br />
<pre class="brush:js">$http.get('/api/data.json').then(
function(response) {
// Do something in success case
},
function(error) {
// Do something in failure case
}).finally(function() {
// Do something after either success or failure
}
);
</pre>
Where and how to use the promise examples above? A typical pattern in AngularJS is to have calls via <span style="color: orange;">$http</span> in a service. Controllers call services and are not aware that <span style="color: orange;">$http</span> is used. Example for <span style="color: orange;">MyController -> MyService -> $http</span>:
<br />
<pre class="brush:js">// In MyService
this.fetchData = function() {
return $http.get('/api/data.json');
};
// In MyController
$scope.fetchData = function() {
MyService.fetchData().then(function(response) {
return response.data;
}, function(error) {
...
}).finally(function() {
...
})
};
</pre>
We have to mention yet that AngularJS' implementation of promises is a subset of the library <a href="https://github.com/kriskowal/q">Q</a>. <span style="color: orange;">Q</span> is the most known implementation of the <span style="color: orange;">Promises/A+</span> specification. That's all for this short post. In the next post, we will meet the AngularJS' <span style="color: orange;">deferred object</span>. A deferred object is an object that exposes a promise as well as the associated methods for resolving / rejecting that promise. It is constructed using the <span style="color: orange;">$q</span> service - the AngularJS' implementation of promises / deferred objects inspired by <span style="color: orange;">Q</span>.<br />
<br />
Stay tuned!Oleg Varaksinhttp://www.blogger.com/profile/13872270134068047346noreply@blogger.com3tag:blogger.com,1999:blog-8492059842142356488.post-38113588343244587142015-07-30T22:23:00.004+02:002016-04-20T22:11:30.861+02:00Magic $parse service in AngularJSAngularJS has a useful, but less documented <a href="https://docs.angularjs.org/api/ng/service/$parse">$parse service</a> 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 <span style="color: orange;">$parse</span>. Furthermore, we will see the differences to the Angular's <span style="color: orange;">$interpolate</span> service and <span style="color: orange;">$eval</span> method.<br />
<br />
<b>Explicitly used $parse</b><br />
<br />
The <span style="color: orange;">$parse</span> compiles an expression to a function which can be then invoked with a <span style="color: orange;">context</span> and <span style="color: orange;">locals</span> in order to retrieve the expression's value. We can imagine this function as a pre-compiled expression. The first parameter is <span style="color: orange;">context</span> - this is an object any expressions embedded in the strings are evaluated against (typically a scope object). The second parameter is <span style="color: orange;">locals</span> - this is an JavaScript object with local variables, useful for overriding values in context.
I've created a simple <a href="http://plnkr.co/edit/V0StdYR0frdTYbDb4sH8?p=preview">plunker</a> to demonstrate the simple usage.
<br />
<pre class="brush:html"><!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>
</pre>
In the HTML we output the controller's variable <span style="color: orange;">parsedMsg</span> which is created in the <span style="color: orange;">app.js</span> as follows:
<br />
<pre class="brush:js">(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);
}
})();
</pre>
As you can see, the expression <span style="color: orange;">'This example uses AngularJS ' + libs.angular.version</span> gets parsed and assigned to the variable template. The template is a function which is invoked with <span style="color: orange;">this</span> object as context. The <span style="color: orange;">this</span> object containes the value of <span style="color: orange;">libs.angular.version</span> (nested objects). This value is used when evaluating the pre-compiled expression. The result is saved in <span style="color: orange;">this.parsedMsg</span> and shown in the HTML.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-ads_lSOxpKI/VbqA-2kwhiI/AAAAAAAAAh0/n6JGjQX7Wc0/s1600/Plunker1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://1.bp.blogspot.com/-ads_lSOxpKI/VbqA-2kwhiI/AAAAAAAAAh0/n6JGjQX7Wc0/s1600/Plunker1.png" /></a></div>
It is important to understand that <span style="color: orange;">$parse</span> can be invoked once and its result (pre-compiled expression) can be used multiple times with different <span style="color: orange;">context</span> (and <span style="color: orange;">locals</span>). The next <a href="http://plnkr.co/edit/IXo5QqKNfhCsnOGLzM4J?p=preview">plunker</a> demonstrates the usage of just one pre-compiled expression with different <span style="color: orange;">locales</span>. The HTML part:
<br />
<pre class="brush:html"><!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>
</pre>
The JavaScript part:
<br />
<pre class="brush:js">(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>';
}
})();
</pre>
As you can see we pass <span style="color: orange;">{i: i}</span> repeatedly as the second parameter, so that the expression <span style="color: orange;">libs[i]</span> is always evaluated with the current value <span style="color: orange;">i</span>. That means <span style="color: orange;">libs[0]</span>, <span style="color: orange;">libs[1]</span>, etc. The result looks like as follows:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-BmgQduWQRLY/VbqCFk4oGuI/AAAAAAAAAiA/ELtW0SFxSts/s1600/Plunker2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://2.bp.blogspot.com/-BmgQduWQRLY/VbqCFk4oGuI/AAAAAAAAAiA/ELtW0SFxSts/s1600/Plunker2.png" /></a></div>
There are some cool things you can do with <span style="color: orange;">$parse</span>. I would like to only list three of them.<br />
<br />
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. <span style="color: orange;">$scope</span>. Example:
<br />
<pre class="brush:js">
$parse('name').assign($scope, 'name2');
</pre>
In the example, the value <span style="color: orange;">name</span> on the <span style="color: orange;">$scope</span> has been changed to <span style="color: orange;">name2</span>.<br />
<br />
2) If we have an object with properties that might be null, no JS errors will be thrown when using <span style="color: orange;">$parse</span>. Instead of that, the result is set to <span style="color: orange;">undefined</span>. In the example above, we had the property <span style="color: orange;">libs.angular.version</span>. The result of
<br />
<pre class="brush:js">
var version = $parse('libs.angular.version')(this);
</pre>
is <span style="color: orange;">version = 1.4.3</span>. If we would use a non exisiting property in the expression, e.g.
<br />
<pre class="brush:js">
var version = $parse('libs.ember.version')(this);
</pre>
the result would be <span style="color: orange;">version = undefined</span>. AngularJS doesn't throw an exception.<br />
<br />
3) Theoretically you can send any logic from backend to the client as string and evaluate the parsed string on the client. Example:
<br />
<pre class="brush:js">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
</pre>
<br />
<b>Implicitly used $parse</b><br />
<br />
AngularJS also uses <span style="color: orange;">$parse</span> 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).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-jeRa93dueic/VbqEjBfx_MI/AAAAAAAAAiM/BF-ND6qPKb4/s1600/Plunker3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://4.bp.blogspot.com/-jeRa93dueic/VbqEjBfx_MI/AAAAAAAAAiM/BF-ND6qPKb4/s1600/Plunker3.png" /></a></div>
The whole code: the HTML page, the color-picker directive and <span style="color: orange;">app.js</span> are demonstrated in my last <a href="http://plnkr.co/edit/4BtuU7eHe2LiUmTQuraS?p=preview">plunker</a>. The page uses the color-picker directive:
<br />
<pre class="brush:html"><!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>
</pre>
The directive's template <span style="color: orange;">colorPickerTemplate.html</span> renders four input sliders, a live preview and current colors and opacity.
<br />
<pre class="brush:html">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 }}
</pre>
The JavaScript part links all together. Whenever a color or opacity is changed, the Angular's <span style="color: orange;">$log</span> service logs current colors and opacity in the browser dev. console. The current colors and opacity are also shown permanently as mentioned above.
<br />
<pre class="brush:js">(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
});
}
}
});
});
}
};
}
})();
</pre>
But stop, where is the magic <span style="color: orange;">$parse</span> here? The directive defines a parameter for an <span style="color: orange;">onchange</span> callback via <span style="color: orange;">onChange: '&'</span>. Behind the scenes, AngularJS parses the passed onchange string, in this case <span style="color: orange;">vm.onColorChange(r,g,b,a)</span>, and creates a function (discussed pre-compiled expression) which can be invoked with the desired <span style="color: orange;">context</span> and <span style="color: orange;">locales</span>. In the directive, we invoke this function with current values for colors <span style="color: orange;">r, g, b</span> and opacity <span style="color: orange;">a</span>.
<br />
<pre class="brush:js">scope.onChange({
'r': scope.r,
'g': scope.g,
'b': scope.b,
'a': scope.a
});
</pre>
<br />
<b>Relation to $interpolate and $eval</b><br />
<br />
<span style="color: orange;">$eval</span> is a method on a scope. It executes an expression on the current scope and returns the result. Example:
<br />
<pre class="brush:js">scope.a = 1;
scope.b = 2;
scope.$eval('a+b'); // result is 3
</pre>
Internally, it uses <span style="color: orange;">$parse</span> for their part.
<br />
<pre class="brush:js">$eval: function(expr, locals) {
return $parse(expr)(this, locals);
}
</pre>
Note, that the <span style="color: orange;">$eval</span> method can not precompile expressions and be used repeatedly. The <span style="color: orange;">$parse</span>, 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 <span style="color: orange;">$eval</span>:
<br />
<pre class="brush:js">var parsedExpression = $parse(...);
var scope1 = $scope.$new();
var scope2 = $scope.$new();
...
var result1 = parsedExpression(scope1);
var result2 = parsedExpression(scope2);
</pre>
There is another high level service - <span style="color: orange;">$interpolate</span>. By means of <span style="color: orange;">$interpolate</span> you can do on-the-fly templating like well-known template engines <a href="http://handlebarsjs.com/">Handlebars</a> or <a href="http://twitter.github.io/hogan.js/">Hogan</a> do that. ES6 has similar <a href="https://hacks.mozilla.org/2015/05/es6-in-depth-template-strings-2/">template strings</a> too. But take a look at one <span style="color: orange;">$interpolate</span> example.
<br />
<pre class="brush:js">(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"
}
})();
</pre>
As you can see, the <span style="color: orange;">$interpolate</span> 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 <span style="color: orange;">{{publisher | uppercase}}</span>. The function can be called again and again with different data objects. The <span style="color: orange;">$interpolate</span> service uses <span style="color: orange;">$parse</span> internally to evaluate individual expressions against the scope. In this regard, the <span style="color: orange;">$interpolate</span> service is normally used as a string-based template language for strings containing multiple expressions. In contrast to <span style="color: orange;">$parse</span>, the <span style="color: orange;">$interpolate</span> is read only.Oleg Varaksinhttp://www.blogger.com/profile/13872270134068047346noreply@blogger.com1tag:blogger.com,1999:blog-8492059842142356488.post-83003294677331754952015-06-14T11:12:00.002+02:002015-06-14T11:24:18.278+02:00Create source maps at project build time for JavaScript debuggingIf 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 "<a href="http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/">Introduction to JavaScript Source Maps</a>", "<a href="http://www.sitepoint.com/enhance-your-javascript-debugging-with-cross-browser-source-maps/">Enhance Your JavaScript Debugging with Cross-Browser Source Maps</a>" and "<a href="http://blog.teamtreehouse.com/introduction-source-maps">An Introduction to Source Maps</a>".<br />
<br />
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 <a href="https://github.com/primefaces-extensions/primefaces-extensions.github.com/wiki/Maven-plugin-for-web-resource-optimization">Maven plugin</a> 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 <span style="color: orange;">sourceMappingURL</span> - the location of the source map. For example: <span style="color: orange;">//# sourceMappingURL=mylib.js.map</span> or <span style="color: orange;">//# sourceMappingURL=/mypath/mylib.js.map</span> or <span style="color: orange;">//# sourceMappingURL=http://sourcemaps/mylib.js.map</span>. 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 <a href="http://cjwainwright.co.uk/webdev/sourcemaps/">here</a> to visualize the entire process.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-u3PEw_AVfcw/VX1CZGKyfhI/AAAAAAAAAg0/9rwiu8nR0j0/s1600/sourcemaps.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-u3PEw_AVfcw/VX1CZGKyfhI/AAAAAAAAAg0/9rwiu8nR0j0/s1600/sourcemaps.png" /></a></div>
<br />
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.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-GQckf59Ak8E/VX1CgDopRyI/AAAAAAAAAg8/6_NN16ffhrQ/s1600/sourcemaps-chrome.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="396" src="http://4.bp.blogspot.com/-GQckf59Ak8E/VX1CgDopRyI/AAAAAAAAAg8/6_NN16ffhrQ/s640/sourcemaps-chrome.png" width="640" /></a></div>
<br />
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 <a href="https://addons.mozilla.org/de/firefox/addon/firebug/">Firebug</a> 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 "<a href="http://www.sitepoint.com/enhance-your-javascript-debugging-with-cross-browser-source-maps/">Enhance Your JavaScript Debugging with Cross-Browser Source Maps</a>" which I mentioned above, has a lot of picture for IE and debugging TypeScript files.<br />
<br />
Source maps can be created during your build. If you work with Node.js and npm, the best tool is <a href="https://github.com/mishoo/UglifyJS2">UglifyJS</a> - a popular command line utility that allows you to combine and compress JavaScript files. If you work with Maven, you can use my <a href="https://github.com/primefaces-extensions/primefaces-extensions.github.com/wiki/Maven-plugin-for-web-resource-optimization">Maven plugin for resource optimization</a> I wrote a some years ago and just updated for supporting source maps. It uses the superb <a href="https://github.com/google/closure-compiler">Google Closure Compiler</a> which offers a support for source map creation and many other cool features. Please refer the documentation of the <a href="https://github.com/primefaces-extensions/primefaces-extensions.github.com/wiki/Maven-plugin-for-web-resource-optimization">Maven plugin</a> to see how to set the various source map configuration options. The simplest configuration which we also use in the current <a href="http://primefaces-extensions.github.io/">PrimeFaces Extensions</a> release looks like as follows:
<br />
<pre class="brush:xml"><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>
</pre>
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: <a href="https://github.com/primefaces-extensions/core/tree/master/src/sourcemap/3.2.0">https://github.com/primefaces-extensions/core/tree/master/src/sourcemap/3.2.0</a> That means, a compressed file, say <span style="color: orange;">timeline.js</span>, has the following line at the end:<br />
<br />
<span style="color: orange;">//# sourceMappingURL=https://raw.githubusercontent.com/primefaces-extensions/core/master/src/sourcemap/3.2.0/timeline.js.map</span><br />
<br />
The source map <span style="color: orange;">timeline.js.map</span> has the content (I truncated some long lines):
<br />
<pre class="brush:plain">{
"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",...]
}
</pre>
It would be probably better to bring these files to a CDN, like <a href="https://github.com/cdnjs/cdnjs">cdnjs</a>, 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 <span style="color: orange;">timeline.js</span> looks in my Firefox.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-mb0hz6lvVW0/VX1EAVHu-nI/AAAAAAAAAhI/wmwDDDaVaPk/s1600/sourceMapDebugging.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="362" src="http://2.bp.blogspot.com/-mb0hz6lvVW0/VX1EAVHu-nI/AAAAAAAAAhI/wmwDDDaVaPk/s640/sourceMapDebugging.png" width="640" /></a></div>
<br />
Due to the Firefox built-in source map support we see the uncompressed JS file <span style="color: orange;">timeline.source.js</span>. I set a breakpoint on the line with the if-statement <span style="color: orange;">if (index < 0)</span>. 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 <span style="color: orange;">index</span> is shown as <span style="color: orange;">a</span> (I marked it red as <span style="color: red;">var index</span>). This is a shortcoming of the current source map specification. You can read <a href="https://code.google.com/p/chromium/issues/detail?id=327092">this discussion</a> for more details.<br />
<br />
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).<br />
<br />
That's all. My next posts will be about AngularJS and less about JSF. Stay tuned.Oleg Varaksinhttp://www.blogger.com/profile/13872270134068047346noreply@blogger.com5tag:blogger.com,1999:blog-8492059842142356488.post-56272319750458632122015-06-10T22:02:00.002+02:002015-06-10T22:02:23.440+02:00PrimeFaces Extensions 3.2.0 releasedDear PrimeFaces community,<br /><br /><a href="http://primefaces-extensions.github.io/">PrimeFaces Extensions</a> 3.2.0 has been released! This is a maintenance release which is built on top of <a href="http://www.primefaces.org/">PrimeFaces</a> 5.2. <a href="https://github.com/primefaces-extensions/primefaces-extensions.github.com/issues?q=milestone%3A3.2.0+is%3Aclosed">Closed issues</a> are available on GitHub.<br /><br />Some notes to the two important changes:<br />
<ul>
<li><span style="color: orange;">pe:ajaxErrorHandler</span> was removed in favor of <span style="color: orange;">p:ajaxExceptionHandler</span>. It was buggy and not working in the prev. release.</li>
<li>Uncompressed JS files are not delivered anymore within JAR files. The
compressed JS files contain <span style="color: orange;">//# sourceMappingURL=...</span> which points to the
appropriate source maps and uncompressed files for debug purpose. <a href="https://github.com/primefaces-extensions/core/tree/master/src/sourcemap/3.2.0">The source maps and uncompressed files</a> are checked in direct in the GitHub and can be fetched from there. That means, uncompressed files have something like at the end:<span style="color: orange;"> <br />//# sourceMappingURL=https://raw.githubusercontent.com/primefaces-extensions/core/master/src/sourcemap/3.2.0/primefaces-extensions.js.map</span><br />More
info about source map is coming soon in my blog and the <a href="https://github.com/primefaces-extensions/primefaces-extensions.github.com/wiki/Maven-plugin-for-web-resource-optimization">Wiki page of the Maven plugin for resource optimization</a>.</li>
</ul>
The deployed showcase will be available soon as usually at <a href="http://primefaces.org/showcase-ext/views/home.jsf">http://primefaces.org/showcase-ext/views/home.jsf</a>.<br />
<br />
Have fun! Oleg Varaksinhttp://www.blogger.com/profile/13872270134068047346noreply@blogger.com0tag:blogger.com,1999:blog-8492059842142356488.post-8966834078953636922015-05-30T00:19:00.000+02:002015-05-30T00:19:19.405+02:00PrimeFaces Cookbook Second Edition has been published<a href="https://www.packtpub.com/application-development/primefaces-cookbook-second-edition">PrimeFaces Cookbook Second Edition</a> was published today. This is an updated second edition of the first PrimeFaces book ever published. <a href="https://www.packtpub.com/application-development/primefaces-cookbook-second-edition">PrimeFaces Cookbook Second Edition</a> covers over 100 effective recipes for <a href="http://www.primefaces.org/">PrimeFaces</a>
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.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/--yA-0baCz3E/VWjjxMBvYcI/AAAAAAAAAgU/H5wJBN8QINk/s1600/3427OS.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="http://4.bp.blogspot.com/--yA-0baCz3E/VWjjxMBvYcI/AAAAAAAAAgU/H5wJBN8QINk/s640/3427OS.jpg" width="515" /></a></div>
<br />
I have updated <a href="http://ova2.github.io/primefaces-cookbook/">the book's homepage</a> with a new table of contents. There are 11 chapters and more than 380 pages. You can download the book's code, clone the <a href="https://github.com/ova2/primefaces-cookbook/tree/second-edition">project on GitHub</a>, compile and run it. Please follow the <a href="https://github.com/ova2/primefaces-cookbook/tree/second-edition">instructions on the GitHub</a>.<br />
<br />
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!Oleg Varaksinhttp://www.blogger.com/profile/13872270134068047346noreply@blogger.com0tag:blogger.com,1999:blog-8492059842142356488.post-38941030588939236122015-04-22T22:22:00.001+02:002015-04-22T22:22:41.877+02:00PrimeFaces Extensions 3.1.0 releasedToday, we released the <a href="http://primefaces-extensions.github.io/">PrimeFaces Extensions</a> 3.1.0. It is built on top of PrimeFaces 5.2 and is fully compatible with PrimeFaces 5.2.<br />
<br />
<a href="https://github.com/primefaces-extensions/primefaces-extensions.github.com/issues?q=milestone%3A3.1.0+is%3Aclosed">Closed issues</a> are available on the GitHub. Please consider some enhancements in the existing components like Timeline, DynaForm, InputNumber and CKEditor. <br />
<br />
The new deployed showcase will be available soon as usually <a href="http://www.primefaces.org/showcase-ext/views/home.jsf">here</a>. The next release will be a maintenance release again.<br />
<br />
Have fun!Oleg Varaksinhttp://www.blogger.com/profile/13872270134068047346noreply@blogger.com5tag:blogger.com,1999:blog-8492059842142356488.post-54070805350611595602015-04-05T22:38:00.001+02:002015-04-05T22:51:53.652+02:00A way to read properties with variable interpolationRecently, I tried to define and read a global properties in an application server. The benefit of such property configured in the application server - it can be shared across all web applications that are deployed on this server. Every deployed application can read the same property which is configured just once at one place. What I tried to do was a system property with another system property in the value part. In the application server JBoss / WildFly, you can e.g. define a system property in the configuration file <span style="color: orange;">standalone.xml</span>. I set the property <span style="color: orange;">exporting.service.config.file</span>.
<br />
<pre class="brush:xml"><system-properties>
<property name="exporting.service.config.file" value="${jboss.server.config.dir}\exporting\exporting-service.properties"/>
</system-properties>
</pre>
<span style="color: orange;">jboss.server.config.dir</span> points to the base configuration directory in JBoss. This property is set automatically by JBoss. In this example, we have a so-called <span style="color: orange;">Variable Interpolation</span>. <a href="http://en.wikipedia.org/wiki/String_interpolation">The definition from the Wikipedia</a>: "Variable interpolation (also variable substitution or variable expansion) is the process of evaluating a string literal containing one or more placeholders, yielding a result in which the placeholders are replaced with their corresponding values". Another example for placeholders <span style="color: orange;">${...}</span> in property value would be the following configuration:
<br />
<pre class="brush:text">application.name=My App
application.version=2.0
application.title=${application.name} ${application.version}
</pre>
When we now try to get the system property from the first example with Java's <span style="color: orange;">System.getProperty(...)</span>
<br />
<pre class="brush:java">
String globalConfigFile = System.getProperty("exporting.service.config.file");
</pre>
we will get the value <span style="color: orange;">${jboss.server.config.dir}\exporting\exporting-service.properties</span>. The placeholder <span style="color: orange;">${jboss.server.config.dir}</span> is not resolved. There are the same troubles in the second example as well.<br />
<br />
What would be the simplest way to read properties with variable interpolation? Well, there is the Spring Framework with <a href="http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/factory/config/PlaceholderConfigurerSupport.html">PlaceholderConfigurerSupport</a> and so on. But it is an overhead to have such big framework as dependency. Is there a lightweight library? Yes, sure - <a href="http://commons.apache.org/proper/commons-configuration/userguide/howto_basicfeatures.html">Apache Commons Configuration</a>. Apache Commons Configuration provides special prefix names for properties to evaluate them in a certain context. There are for instance:<br />
<ul>
<li><span style="color: orange;">sys:</span> This prefix marks a variable to be a system property. Commons Configuration will search for a system property with the given name and replace the variable by its value.</li>
<li><span style="color: orange;">const:</span> The prefix indicates that a variable is to be interpreted as a constant member field of a class. The name of the variable must be fully qualified class name.</li>
<li><span style="color: orange;">env:</span> The prefix references OS-specific environment properties.</li>
</ul>
Some examples from the documentation:
<br />
<pre class="brush:text">user.file = ${sys:user.home}/settings.xml
action.key = ${const:java.awt.event.KeyEvent.VK_CANCEL}
java.home = ${env:JAVA_HOME}
</pre>
Now, I could add the needed dependency to my Maven project
<br />
<pre class="brush:xml"><dependency>
<groupId>commons-configuration</groupId>
<artifactId>commons-configuration</artifactId>
<version>1.10</version>
</dependency>
</pre>
set the prefix <span style="color: orange;">sys:</span> before <span style="color: orange;">jboss.server.config.dir</span>
<br />
<pre class="brush:xml"><system-properties>
<property name="exporting.service.config.file" value="${sys:jboss.server.config.dir}\exporting\exporting-service.properties"/>
</system-properties>
</pre>
and write the following code
<br />
<pre class="brush:java">import org.apache.commons.configuration.SystemConfiguration;
...
SystemConfiguration systemConfiguration = new SystemConfiguration();
String globalConfigFile = systemConfiguration.getString("exporting.service.config.file");
...
</pre>
The String <span style="color: orange;">globalConfigFile</span> on my notebook has the value <span style="color: orange;">C:\Development\Servers\jboss-as-7.1.1.Final\standalone\configuration\exporting\exporting-service.properties</span>. The prefix <span style="color: orange;">sys:</span> marks a variable to be a system property. Commons Configuration will search for a system property with the given name and replace the variable by its value. The complete code:
<br />
<pre class="brush:java">import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.configuration.SystemConfiguration;
...
PropertiesConfiguration propertiesConfiguration = new PropertiesConfiguration();
SystemConfiguration systemConfiguration = new SystemConfiguration();
String globalConfigFile = systemConfiguration.getString("exporting.service.config.file");
if (globalConfigFile != null) {
try {
propertiesConfiguration.setDelimiterParsingDisabled(true);
propertiesConfiguration.load(globalConfigFile);
} catch (ConfigurationException e) {
LOG.log(Level.INFO, "Cannot read global properties");
}
}
</pre>
Any single property can be read e.g. as
<br />
<pre class="brush:java">propertiesConfiguration.getString("someKey")
propertiesConfiguration.getString("someKey", someDefaultValue)
propertiesConfiguration.getBoolean("someKey")
propertiesConfiguration.getBoolean("someKey", someDefaultValue)
propertiesConfiguration.getInteger("someKey")
propertiesConfiguration.getInteger("someKey", someDefaultValue)
</pre>
usw. That's all. Let me know if you know another simple ways to read properties with variable interpolation.Oleg Varaksinhttp://www.blogger.com/profile/13872270134068047346noreply@blogger.com1tag:blogger.com,1999:blog-8492059842142356488.post-13828952299651168862015-04-03T13:53:00.003+02:002015-04-03T14:10:36.814+02:00Caching of web content with Spring's cache manager<br />
I this post, I would like to show basics how to cache and manage the caching of web content with Spring's <span style="color: orange;">CacheManager</span>, <span style="color: orange;">@Cacheable</span> and <span style="color: orange;">JMX</span> annotations. Imagine a web shop which fetches some content, such as header, footer, teasers, main navigation, from a remote WCMS (Web Content Management System). The fetching may e.g. happen via a REST service. Some content is rarely updated, so that it makes sense to cache it in the web application due to performance reasons.<br />
<br />
<b>Getting Started</b><br />
<br />
First, we need a cache provider. A good cache provider would be <a href="http://ehcache.org/">EhCache</a>. You need to add the <span style="color: orange;">EhCache</span> <a href="http://ehcache.org/code">as dependency</a> to your project. You also need to configure <span style="color: orange;">ehcache.xml</span> which describes, among other things, the cache name(s), where and how long the cached content is stored. Please refer to the <a href="http://ehcache.org/documentation">documentation</a> to learn how the <span style="color: orange;">ehcache.xml</span> looks like. The central class of the <span style="color: orange;">EhCache</span> is the <span style="color: orange;">net.sf.ehcache.CacheManager</span>. With help of this class you can add or remove any objects to / from the cache and much more programmatically. Objects can be cached in memory, on the disk or somewhere else.<br />
<br />
The <a href="http://projects.spring.io/spring-framework/">Spring framework</a> provides a <span style="color: orange;">CacheManager</span> backed by the <span style="color: orange;">EhCache</span> - <span style="color: orange;">org.springframework.cache.CacheManager</span>. It also provides the <span style="color: orange;">@Cacheable</span> annotation. From the <a href="http://docs.spring.io/spring/docs/current/spring-framework-reference/html/cache.html">documentation</a>: "As the name implies, <span style="color: orange;">@Cacheable</span> is used to demarcate methods that are cacheable - that is, methods for whom the result is stored into the cache so on subsequent invocations (with the same arguments), the value in the cache is returned without having to actually execute the method. In its simplest form, the annotation declaration requires the name of the cache associated with the annotated method". We will use the JMX annotations as well. These are Spring's annotations <span style="color: orange;">@ManagedResource</span> and <span style="color: orange;">@ManagedOperation</span>. Why do we need those? We need them to be able to clear cache(s) via an JMX console. Why? Well, e.g. the underlying data have been changed, but the cache is not expired yet. The outdated data will be still read from the cache and not from the native source. The beans annotated with <span style="color: orange;">@ManagedResource</span> will be exposed as JMX beans and methods annotated by <span style="color: orange;">@ManagedOperation</span> can be executed via an JMX console. I recommend to use <a href="https://code.google.com/p/jminix/">JMiniX</a> as a simple JMX entry point. Embedding JMiniX in a webapp is done simply by declaring a servlet. Parametrized methods are supported as well, so that you can even input some real values for method's parameters and trigger the execution with these values.<br />
<br />
<b>How to do it...</b><br />
<br />
Now we are ready to develop the first code. We need a service which communicates with a remote backend in order to fetch various contents from the WCMS. Let's show exemplary a basic code with one method <span style="color: orange;">fetchMainNavigation()</span>. This method fetches the structure of the main navigation menu and converts the structure to a DTO object <span style="color: orange;">NavigationContainerDTO</span> (model class for the menu). The whole business and technical logic is resided in the bean <span style="color: orange;">MainNavigationHandler</span>. This logic is not important for this blog post. The method <span style="color: orange;">fetchMainNavigation()</span> expects two parameters: locale (e.g. English or German) and variant (e.g. B2C or B2B shop).
<br />
<pre class="brush:java">@Component
public class WCMSServiceImpl extends BaseService implements WCMSService {
// injection of Spring's CacheManager is needed for @Cacheable
@Autowired
private CacheManager cacheManager;
@Autowired
private MainNavigationHandler mainNavigationHandler;
...
@Override
@Cacheable(value = "wcms-mainnavigation",
key = "T(somepackage.wcms.WCMSBaseHandler).cacheKey(#root.methodName, #root.args[0], #root.args[1])")
public NavigationContainerDTO fetchMainNavigation(Locale lang, String variant) {
Object[] params = new Object[0];
if (lang != null) {
params = ArrayUtils.add(params, lang);
}
if (variant != null) {
params = ArrayUtils.add(params, variant);
}
return mainNavigationHandler.get("fetchMainNavigation", params);
}
}
</pre>
The method is annotated with the Spring's annotation <span style="color: orange;">@Cacheable</span>. That means, the returned object <span style="color: orange;">NavigationContainerDTO</span> will be cached if it was not yet available in the cache. The next fetching will return the object from the cache until the cache gets expired. The caching occurs according to the settings in the <span style="color: orange;">ehcache.xml</span>. Spring's <span style="color: orange;">CacheManager</span> finds the <span style="color: orange;">EhCache</span> provider automatically in the classpath.
The value attribute in <span style="color: orange;">@Cacheable</span> points to the cache name. The key attribute points to the key in the cache the object can be accessed by. Since caches are essentially key-value stores, each invocation of a cached method needs to be translated into a suitable key for the cache access. In a simple case, the key can be any static string. In the example, we need a dynamic key because the method has two parameters: locale and variant. Fortunately, Spring supports dynamic keys with <span style="color: orange;">SpEL expression</span> (Spring EL expression). See the table "<a href="http://docs.spring.io/spring/docs/current/spring-framework-reference/html/cache.html#cache-spel-context">Cache SpEL available metadata</a>" for more details. You can invoke any static method generating the key. Our expression <span style="color: orange;">T(somepackage.wcms.WCMSBaseHandler).cacheKey(#root.methodName, #root.args[0], #root.args[1])</span> means we call the static method <span style="color: orange;">cacheKey</span> in the class <span style="color: orange;">WCMSBaseHandler</span> with three parameters: the method name, first and second arguments (locale and variant respectively). This is our key generator.
<br />
<pre class="brush:java">public static String cacheKey(String method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(method);
if (params != null && params.length > 0) {
for (Object param : params) {
if (param != null) {
sb.append("-");
sb.append(param.toString());
}
}
}
return sb.toString();
}
</pre>
Let's show how the handler class <span style="color: orange;">MainNavigationHandler</span> looks like. This is just a simplified example from a real project.
<br />
<pre class="brush:java">
@Component
@ManagedResource(objectName = "bean:name=WCMS-MainNavigation",
description = "Manages WCMS-Cache for the Main-Navigation")
public class MainNavigationHandler extends WCMSBaseHandler<NavigationContainerDTO, Navigation> {
@Override
NavigationContainerDTO retrieve(Objects... params) {
// the logic for content retrieving and DTOs mapping is placed here
...
}
@ManagedOperation(description = "Delete WCMS-Cache")
public void clearCache() {
Cache cache = cacheManager.getCache("wcms-mainnavigation");
if (cache != null) {
cache.clear();
}
}
}
</pre>
The CacheManager is also available here thanks to the following injection in the <span style="color: orange;">WCMSBaseHandler</span>.
<br />
<pre class="brush:java">@Autowired
private CacheManager cacheManager;
</pre>
<span style="color: orange;">@ManagedResource</span> is the Spring's JMX annotation, so that the beans are exported as JMX MBean and become visible in the JMX console. The method to be exported should be annotated with <span style="color: orange;">@ManagedOperation</span>. This is the methode <span style="color: orange;">clearCache()</span> which removes all content for the main navigation from the cache. "All content" means an object of type <span style="color: orange;">NavigationContainerDTO</span>.
The developed WCMS service can be now injected into a bean on the front-end side. I already blogged about <a href="http://ovaraksin.blogspot.de/2014/12/building-dynamic-responsive-multi-level.html">how to build a multi-level menu with plain HTML</a> and shown the code. This is exactly the main navigation from this service.<br />
<br />
<b>There is more...</b><br />
<br />
The scanning of JMX annotations should be configured in a Spring's XML configuration file.
<br />
<pre class="brush:xml"><bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="server" ref="mbeanServer"/>
<property name="assembler" ref="assembler"/>
<property name="namingStrategy" ref="namingStrategy"/>
<property name="autodetect" value="true"/>
</bean>
</pre>
The JMX console of the <a href="https://code.google.com/p/jminix/">JMiniX</a> is reachable under the <span style="color: orange;">http(s)://</span><host><span style="color: orange;">:</span><port><span style="color: orange;">/mct/webshop/admin/jmx/</span> A click on the <span style="color: orange;">execute</span> button of the <span style="color: orange;">clearCache()</span> method triggers the cache clearing.</port></host><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-vqCo5OAl1OE/VR5_JhGDVlI/AAAAAAAAAek/xhN2LSH4Z1g/s1600/jmxBeans.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-vqCo5OAl1OE/VR5_JhGDVlI/AAAAAAAAAek/xhN2LSH4Z1g/s1600/jmxBeans.png" height="358" width="640" /></a></div>
Oleg Varaksinhttp://www.blogger.com/profile/13872270134068047346noreply@blogger.com3tag:blogger.com,1999:blog-8492059842142356488.post-30965209579339007732015-03-07T18:18:00.001+01:002015-03-08T12:09:48.400+01:00HTTP web server for Chrome to test local web applicationsIf you are writing HTML and JavaScript on your PC and testing the output in your browser without setting up a server, you will probably get some error messages about <span style="color: orange;">Cross Origin Requests</span>. Your browser will render HTML, run JavaScript, jQuery or AngularJS web app, and ... block requests. This is a common behavior of many web browsers due to possible cross site attacks. That is understandable because it is not clever to allow someone to read your hard drive from your web browser. Right?<br />
<br />
More concrete example. Assume, you develop an AngularJS web app with custom directives. Maybe you're quickly testing some AngularJS features without any web server. AngularJS loads HTML files of custom directives on page initial load. All files are loaded by AJAX from your PC, so that you will see an error message such as <span style="color: orange;">"XMLHttpRequest cannot load file:///C:/somefolder/somefile.html"</span>. I had e.g. these messages in the browser console:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-rN5sgOwmDYk/VPsvnLdk_-I/AAAAAAAAAdY/h9ILP7NdhLY/s1600/load_error_angularjs.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-rN5sgOwmDYk/VPsvnLdk_-I/AAAAAAAAAdY/h9ILP7NdhLY/s1600/load_error_angularjs.png" height="124" width="640" /></a></div>
<br />
This is because your browser doesn't allow AJAX requests for <span style="color: orange;">file:///</span> Obviously, you need to serve all files over HTTP. The simplest solution would be to install <a href="https://chrome.google.com/webstore/detail/web-server-for-chrome/ofhbbkphhbklhfoeikjpcbhemlocgigb?hl=en">a web server for Chrome</a>. It serves web pages from a local folder over the network, using HTTP and comes exactly to rescue. After installing this small server app from the <a href="https://chrome.google.com/webstore/detail/web-server-for-chrome/ofhbbkphhbklhfoeikjpcbhemlocgigb?hl=en">Google Web Store</a>, you will see a Web Server icon. I have e.g. something like<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-bHgmI97KK6U/VPswB-qGeqI/AAAAAAAAAdg/Lg_LztkE2Wk/s1600/chrome_app_launcher.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-bHgmI97KK6U/VPswB-qGeqI/AAAAAAAAAdg/Lg_LztkE2Wk/s1600/chrome_app_launcher.png" /></a></div>
<br />
Open the web server for Chrome and choose a directory to serve static content. In our case, this is the main folder of your project.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-08Hg2-6baCU/VPswMP7TtQI/AAAAAAAAAdo/TiAbOl3yGsI/s1600/chrome_web_server.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-08Hg2-6baCU/VPswMP7TtQI/AAAAAAAAAdo/TiAbOl3yGsI/s1600/chrome_web_server.png" height="279" width="640" /></a></div>
<br />
It is now able to stream large files and handle range requests. It also sets mime types correctly. Navigate to <span style="color: orange;">http://127.0.0.1:8887</span> You will see all content of you project. Assume, the main file is called <span style="color: orange;">myapp.html</span>. After choosing this file, you will see the URL <span style="color: orange;">http://127.0.0.1:8887/myapp.html</span> The web app is fine now because all separate files for AngularJS's includes or directives are streamed down by AJAX over HTTP. Changes in files are visible on-the-fly without any restarts or redeployments.<br />
<br />
Have fun!Oleg Varaksinhttp://www.blogger.com/profile/13872270134068047346noreply@blogger.com4tag:blogger.com,1999:blog-8492059842142356488.post-21552922021495425722015-02-01T00:10:00.002+01:002015-02-01T00:21:46.401+01:00JavaScript Closures: Pass parameters to callbacksMany JavaScript libraries allow to define callbacks. We often need to pass various parameters oder some context from outside to the same callbacks. <a href="https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Closures">JavaScript Closures</a> makes it possible. The idea is to define two functions - one outer and one inner which acts as callback. The outer function can take parameters and pass them to the inner function. Thanks to Closures, the inner function can access the parameters in the parent scope. The outer function should now returns the inner one. That is actually a well-known trick.<br />
<br />
Assume you use the <a href="http://select2.github.io/">Select2</a> plugin and want to have two callbacks. One is defined via the option <span style="color: orange;">templateResult</span> and used for formatting select items in dropdown. Another is defined via the option <span style="color: orange;">templateSelection</span> and used for formatting the displayed value in select field.
<br />
<pre class="brush:js">$(this).select2({
...
templateResult: formatResultTemplate,
templateSelection: formatSelectionTemplate
});
function formatResultTemplate(data) {
...
}
function formatSelectionTemplate(data) {
...
}
</pre>
Assume, in both cases, the HTML code and formatting are similar except small differences in CSS styles. The functions have much repeated code and we would like to follow the <span style="color: orange;">don't-repeat-yourself principle</span> (DRY). What is about to pass CSS style as parameter? And here you go (real example from project).
<br />
<pre class="brush:js">$(this).select2({
...
templateResult: formatTemplate('margin:0 6px 0 0;'),
templateSelection: formatTemplate('height:28px;')
});
function formatTemplate(style) {
function formatWithStyle(data) {
var imgSrc = $(data.element).data('image');
if (imgSrc) {
return "<img src='" + imgSrc + "' style='" + style + "'/>;<span class='option-text'>" + data.text + "</span>;";
} else {
return "<span class='option-text'>" + data.text + "</span>";
}
}
return formatWithStyle;
}</pre>
The code is optimized now. The outer function <span style="color: orange;">formatTemplate</span> returns the inner one <span style="color: orange;">formatWithStyle</span>, "parametrized" with style. This inner function can be reused as "formatting callback".<br />
<br />
I hope you got the idea.Oleg Varaksinhttp://www.blogger.com/profile/13872270134068047346noreply@blogger.com1tag:blogger.com,1999:blog-8492059842142356488.post-3825859860797703422015-01-25T00:30:00.000+01:002015-01-25T00:44:02.737+01:00PrimeFaces: Opening external pages in dynamically generated dialogI already blogged about <a href="http://ovaraksin.blogspot.de/2015/01/extending-primefaces-csv-with-bean.html">one recipe</a> in the upcomming 2. edition of the <a href="https://www.packtpub.com/web-development/primefaces-cookbook">PrimeFaces Cookbook</a>. In this post, I would like to post the second recipe about a small framework called <span style="color: orange;">Dialog Framework</span>. I personally like it because I remember my costly effort to do the same thing with the Struts Framework. When you wanted to load an external page into a popup and submit some data to this page, you had to call <span style="color: orange;">window.open</span> with an hidden form, set passed values into hidden fields, submit the form to the external page via JavaScript and wait until the page is ready to use in <span style="color: orange;">window.onload</span> or <span style="color: orange;">document.ready</span>. A lot of manuelly work. PrimeFaces does this job for you and, in addition, provides with <span style="color: orange;">p:dialog</span> a beautiful user interface as replacement for popup.<br />
<br />
The regular usage of PrimeFaces' dialog is a declarative approach with <span style="color: orange;">p:dialog</span>. Beside this declarative approach, there is a programmatic approach as well. The programmatic approach is based on a programmatic API where dialogs are created and destroyed at runtime. It is called <span style="color: orange;">Dialog Framework</span>. The Dialog Framework is used to open external pages in dynamically generated dialog. The usage is quite simple, <span style="color: orange;">RequestContext</span> provide two methods: <span style="color: orange;">openDialog</span> and <span style="color: orange;">closeDialog</span> that allow opening and closing dynamic dialogs. Furthermore, the Dialog Framework makes possible to pass data back from the page displayed in the dialog to the caller page.<br />
<br />
In this recipe, we will demonstrate all features available in the Dialog Framework. We will open a dialog with options programmatically and pass parameters to the page displayed in this dialog. We will also meet the possibility for communicating between the source (caller) page and the dialog.<br />
<br />
<b>Getting ready</b><br />
<br />
Dialog Framework requires the following configuration in <span style="color: orange;">faces-config.xml</span>:
<br />
<pre class="brush:xml"><application>
<action-listener>org.primefaces.application.DialogActionListener</action-listener>
<navigation-handler>org.primefaces.application.DialogNavigationHandler</navigation-handler>
<view-handler>org.primefaces.application.DialogViewHandler</view-handler>
</application>
</pre>
<br />
<b>How to do it...</b><br />
<br />
We will develop a page with radio buttons to select one available PrimeFaces' book for rating. The rating itself happens in a dialog after a click on the button <span style="color: orange;">Rate the selected book</span>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-99_537n5zA0/VMQl8bzuveI/AAAAAAAAAco/LJwEKQ9yFcc/s1600/3427_11_04.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-99_537n5zA0/VMQl8bzuveI/AAAAAAAAAco/LJwEKQ9yFcc/s1600/3427_11_04.png" /></a></div>
The XHTML snippet to the screenshot is listed below.
<br />
<pre class="brush:xhtml"><p:messages id="messages" showSummary="true" showDetail="false"/>
<p:selectOneRadio id="books" layout="pageDirection" value="#{dialogFrameworkBean.bookName}">
<f:selectItem itemLabel="PrimeFaces Cookbook" itemValue="PrimeFaces Cookbook"/>
<f:selectItem itemLabel="PrimeFaces Starter" itemValue="PrimeFaces Starter"/>
<f:selectItem itemLabel="PrimeFaces Beginner's Guide" itemValue="PrimeFaces Beginner's Guide"/>
<f:selectItem itemLabel="PrimeFaces Blueprints" itemValue="PrimeFaces Blueprints"/>
</p:selectOneRadio>
<p:commandButton value="Rate the selected book"
process="@this books"
actionListener="#{dialogFrameworkBean.showRatingDialog}"
style="margin-top: 15px">
<p:ajax event="dialogReturn" update="messages" listener="#{dialogFrameworkBean.onDialogReturn}"/>
</p:commandButton>
</pre>
The page in the dialog is a full page <span style="color: orange;">bookRating.xhtml</span> with a <span style="color: orange;">Rating</span> component <span style="color: orange;">p:rating</span>. It also shows the name of the book selected for rating.
<br />
<pre class="brush:html"><!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:p="http://primefaces.org/ui">
<f:view contentType="text/html" locale="en">
<f:metadata>
<f:viewParam name="bookName" value="#{bookRatingBean.bookName}"/>
</f:metadata>
<h:head>
<title>Rate the book!</title>
</h:head>
<h:body>
<h:form>
What is your rating for the book <strong>#{bookRatingBean.bookName}</strong>?
<p/>
<p:rating id="rating">
<p:ajax event="rate" listener="#{bookRatingBean.onrate}"/>
<p:ajax event="cancel" listener="#{bookRatingBean.oncancel}"/>
</p:rating>
</h:form>
</h:body>
</f:view>
</html>
</pre>
The next screenshot demonstrates how the dialog looks like.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-rlhcvozpwDY/VMQnIp2BptI/AAAAAAAAAc0/O9iV8DIB2fM/s1600/3427_11_05.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-rlhcvozpwDY/VMQnIp2BptI/AAAAAAAAAc0/O9iV8DIB2fM/s1600/3427_11_05.png" /></a></div>
<br />
A click on a rating star or the cancel symbol closes the dialog. The source (caller) page displays a message with the selected rating value in the range from 0 till 5.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-KQ1O8tDXZTQ/VMQnZCHDHhI/AAAAAAAAAc8/rPZoVjIngPw/s1600/3427_11_06.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-KQ1O8tDXZTQ/VMQnZCHDHhI/AAAAAAAAAc8/rPZoVjIngPw/s1600/3427_11_06.png" /></a></div>
The most interesting part is the logic in beans. The bean <span style="color: orange;">DialogFrameworkBean</span> opens the rating page within the dialog by invoking the method <span style="color: orange;">openDialog()</span> with the outcome, options and POST parameters on a <span style="color: orange;">RequestContext</span> instance. Furthermore, the bean defines an AJAX listener <span style="color: orange;">onDialogReturn()</span> which is invoked when the data (selected rating) is returned from the dialog after it was closed.
<br />
<pre class="brush:java">@Named
@ViewScoped
public class DialogFrameworkBean implements Serializable {
private String bookName;
public void showRatingDialog() {
Map<String, Object> options = new HashMap<String, Object>();
options.put("modal", true);
options.put("draggable", false);
options.put("resizable", false);
options.put("contentWidth", 500);
options.put("contentHeight", 100);
options.put("includeViewParams", true);
Map<String, List<String>> params = new HashMap<String, List<String>>();
List<String> values = new ArrayList<String>();
values.add(bookName);
params.put("bookName", values);
RequestContext.getCurrentInstance().openDialog("/views/chapter11/bookRating", options, params);
}
public void onDialogReturn(SelectEvent event) {
Object rating = event.getObject();
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO, "You rated the book with " + rating, null);
FacesContext.getCurrentInstance().addMessage(null, message);
}
// getters / setters
...
}
</pre>
The bean <span style="color: orange;">BookRatingBean</span> defines two listeners for the <span style="color: orange;">Rating</span> component. They are invoked when the user clicks on a star and the cancel symbol respectively. We call there <span style="color: orange;">closeDialog()</span> on a <span style="color: orange;">RequestContext</span> instance to trigger the dialog closing and to pass the current rating value to the mentioned listener <span style="color: orange;">onDialogReturn()</span>.
<br />
<pre class="brush:java">@Named
@RequestScoped
public class BookRatingBean {
private String bookName;
public void onrate(RateEvent rateEvent) {
RequestContext.getCurrentInstance().closeDialog(rateEvent.getRating());
}
public void oncancel() {
RequestContext.getCurrentInstance().closeDialog(0);
}
// getters / setters
...
}
</pre>
<br />
<b>How it works...</b><br />
<br />
The <span style="color: orange;">RequestContext</span> provides two methods of the same name <span style="color: orange;">openDialog</span> to open a dialog dynamically at runtime. The first one only has one parameter - the logical outcome used to resolve a navigation case. The second one has three parameters - outcome, dialog's configuration options and parameters that are sent to the view displayed in the dialog. We used the second variant in the example. The options are put into a <span style="color: orange;">Map</span> as key, value pairs. The parameters are put into a <span style="color: orange;">Map</span> too. In our case, we put the name of the selected book. After that, the name is received in the dialog's page <span style="color: orange;">bookRating.xhtml</span> via the <span style="color: orange;">f:viewParam</span>. <span style="color: orange;">f:viewParam</span> sets the transferred parameter into the <span style="color: orange;">BookRatingBean</span>, so that it is available in the heading above the <span style="color: orange;">Rating</span> component. <u>Tip</u>: Please refer the <a href="http://primefaces.org/documentation.html">PrimeFaces User's Guide</a> to see a full list of supported dialog's configuration options.<br />
<br />
Let us go through the request-response life cycle. Once the response is received from the request caused by the command button, a dialog gets created with an <span style="color: orange;">iframe</span> inside. The URL of the <span style="color: orange;">iframe</span> points to the full page, in our case <span style="color: orange;">bookRating.xhtml</span>. The page will be streamed down and shown in the dialog. As you can see, there are always two requests: the first initial POST and the second GET sending by iframe. Note that the Dialog Framework only works with initial AJAX requests. Non-AJAX request are ignored. Please also note the the title of the dialog is taken from the HTML <span style="color: orange;">title</span> element.<br />
<br />
As we already mentioned above, the dialog can be closed programmatically by invoking the method <span style="color: orange;">closeDialog</span> on a <span style="color: orange;">RequestContext</span> instance. On the caller page, the button that triggers the dialog needs to have an AJAX listener for the <span style="color: orange;">dialogReturn</span> event to be able to receive any data from the dialog. The data is passed as parameter to the method <span style="color: orange;">closeDialog(Object data)</span>. In the example, we pass either a positive integer value <span style="color: orange;">rateEvent.getRating()</span> or <span style="color: orange;">0</span>.Oleg Varaksinhttp://www.blogger.com/profile/13872270134068047346noreply@blogger.com2tag:blogger.com,1999:blog-8492059842142356488.post-19942907121242935332015-01-02T19:01:00.005+01:002015-01-02T19:05:54.124+01:00Extending PrimeFaces CSV with Bean ValidationSome of you already know that me and my co-author Mert Çalışkan are working on the 2. edition of the <a href="https://www.packtpub.com/web-development/primefaces-cookbook">PrimeFaces Cookbook</a>. The <a href="https://www.packtpub.com/">Packt Publishing</a> allowed me to publish a small excerpt from one recipe of the new chapter "Client Side Validation". It would help in letting the readers know about the book's content. In this blog post, I would like to discuss the extending PrimeFaces Client Side Validation (CSV) with Bean Validation.<br />
<br />
<a href="http://beanvalidation.org/">Bean Validation</a> is a validation model available as part of Java EE 6 platform, which allows the validation by constraints in the form of annotations placed on a field, method, or class. JSF 2.2 supports the validation placed on fields (properties and their getters / setters) in managed beans, as well as Spring or CDI beans. The validation on class level is not supported yet, as long you do not use utilities such as <a href="http://showcase.omnifaces.org/validators/validateBean">OmniFaces</a>.<br />
<br />
PrimeFaces’ CSV has a built-in integration with Bean Validation. Constraints defined with annotations can be validated on the client-side by the CSV framework. Though the Bean Validation API defines a whole set of standard constraint annotations one can easily think of situations in which these standard annotations will not suffice. For these cases, you are able to create custom constraints for specific validation requirements. Client Side Validation API in PrimeFaces works seamlessly with custom constraints.<br />
<br />
In this recipe, we will develop a special custom constraint and validators for validating a card verification code (<a href="http://en.wikipedia.org/wiki/Card_security_code">CVC</a>). CVC is used as security feature with bank card number. It is a number with a length between three and four digits. For instance, MasterCard or Visa require three digits and American Express requires four digits. Therefore, the CVC validation will depend on the selected bank card. User can select a bank card by a <span style="color: orange;">p:selectOneMenu</span>, type a CVC into a<span style="color: orange;"> p:inputText</span> and submit the inputs after that.<br />
<br />
<span style="font-family: Verdana,sans-serif;"><b>How to do it...</b></span><br />
<br />
We will start with a custom annotation used for CVC field.
<br />
<pre class="brush:java">import org.primefaces.validate.bean.ClientConstraint;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
@Constraint(validatedBy = CvcConstraintValidator.class)
@ClientConstraint(resolvedBy = CvcClientConstraint.class)
@Target({FIELD, METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidCVC {
String message() default "{invalid.cvc.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
// identifier of the select menu with cards
String forCardMenu() default "";
}
</pre>
<span style="color: orange;">@Constraint</span> is a regular annotation from the Bean Validation API and <span style="color: orange;">@ClientConstraint</span> is one from the PrimeFaces CSV Framework, which helps to resolve metadata. The developed annotation defines the message key <span style="color: orange;">invalid.cvc.message</span> and has the custom property <span style="color: orange;">forCardMenu</span>. The value of this property is any search expression in terms of <span style="color: orange;">PrimeFaces Selectors (PFS)</span> to reference the select menu with bank cards. This is necessary because the valid CVC value depends on the selected card.<br />
<br />
The goal of <span style="color: orange;">CvcConstraintValidator</span> is the validation of the input length.
<br />
<pre class="brush:java">public class CvcConstraintValidator implements ConstraintValidator<ValidCVC, Integer> {
@Override
public void initialize(ValidCVC validCVC) {
}
@Override
public boolean isValid(Integer cvc, ConstraintValidatorContext context) {
if (cvc == null || cvc < 0) {
return false;
}
int length = (int) (Math.log10(cvc) + 1);
return (length >= 3 && length <= 4);
}
}
</pre>
The goal of the <span style="color: orange;">CvcClientConstraint</span> is the preparing of metadata.
<br />
<pre class="brush:java">public class CvcClientConstraint implements ClientValidationConstraint {
private static final String CARDMENU_METADATA = "data-forcardmenu";
@Override
public Map<String, Object> getMetadata(ConstraintDescriptor constraintDescriptor) {
Map<String, Object> metadata = new HashMap<String, Object>();
Map attrs = constraintDescriptor.getAttributes();
String forCardMenu = (String) attrs.get("forCardMenu");
if (StringUtils.isNotBlank(forCardMenu)) {
metadata.put(CARDMENU_METADATA, forCardMenu);
}
return metadata;
}
@Override
public String getValidatorId() {
return ValidCVC.class.getSimpleName();
}
}
</pre>
Let us go to the client-side implementation. First, we have to create a JavaScript file, say <span style="color: orange;">validators.js</span>, and register there our own validator in the namespace <span style="color: orange;">PrimeFaces.validator</span> with the name <span style="color: orange;">ValidCVC</span>. This name is an unique ID returned by the method <span style="color: orange;">getValidatorId()</span> (see the class <span style="color: orange;">CvcClientConstraint</span>). The function to be implemented is called <span style="color: orange;">validate()</span>. It has two parameters: the element itself and the current input value to be validated.
<br />
<pre class="brush:js">PrimeFaces.validator['ValidCVC'] = {
MESSAGE_ID: 'invalid.cvc',
validate: function (element, value) {
// find out selected menu value
var forCardMenu = element.data('forcardmenu');
var selOption = forCardMenu ?
PrimeFaces.expressions.SearchExpressionFacade.
resolveComponentsAsSelector(forCardMenu).find("select").val() : null;
var valid = false;
if (selOption && selOption === 'MCD') {
// MasterCard
valid = value > 0 && value.toString().length == 3;
} else if (selOption && selOption === 'AMEX') {
// American Express
valid = value > 0 && value.toString().length == 4;
}
if (!valid) {
throw PrimeFaces.util.ValidationContext.
getMessage(this.MESSAGE_ID);
}
}
};
</pre>
Second, we have to create a JavaScript file for localized messages, e.g. <span style="color: orange;">lang_en.js</span>.
<br />
<pre class="brush:js">PrimeFaces.locales['en'] = {
messages : PrimeFaces.locales['en_US'].messages
};
$.extend(PrimeFaces.locales['en'].messages, {
...
'invalid.cvc':
'Card Validation Code is invalid'
});
</pre>
The bean has two required properties annotated with <span style="color: orange;">@NotNull</span>. In addition, the property <span style="color: orange;">cvc</span> is annotated with our custom annotation <span style="color: orange;">@ValidCVC</span>. The value of the attribute <span style="color: orange;">forCardMenu</span> points to the style class of the <span style="color: orange;">p:selectOneMenu</span> that lists available bank cards.
<br />
<pre class="brush:java">@Named
@ViewScoped
public class ExtendCsvBean implements Serializable {
@NotNull
private String card;
@NotNull
@ValidCVC(forCardMenu = "@(.card)")
private Integer cvc;
public void save() {
RequestContext.getCurrentInstance().execute("alert('Saved!')");
}
// getters / setters
...
}
</pre>
In the XHTML fragment, we have a select menu with two bank cards and an input field for CVC. The <span style="color: orange;">p:commandButton</span> validates the fields and executes the method <span style="color: orange;">save()</span> on postback.
<br />
<pre class="brush:xhtml"><h:panelGrid id="pgrid" columns="3" cellpadding="3" style="margin-bottom:10px;">
<p:outputLabel for="card" value="Card"/>
<p:selectOneMenu id="card" styleClass="card"
value="#{extendCsvBean.card}">
<f:selectItem itemLabel="Please select a card"
itemValue="#{null}"/>
<f:selectItem itemLabel="MasterCard"
itemValue="MCD"/>
<f:selectItem itemLabel="American Express"
itemValue="AMEX"/>
</p:selectOneMenu>
<p:message for="card"/>
<p:outputLabel for="cvc" value="CVC"/>
<p:inputText id="cvc" value="#{extendCsvBean.cvc}"/>
<p:message for="cvc"/>
</h:panelGrid>
<p:commandButton validateClient="true" value="Save"
process="@this pgrid" update="pgrid" action="#{extendCsvBean.save}"/>
</pre>
<u>Note:</u> As you can see, neither <span style="color: orange;">p:selectOneMenu</span> nor <span style="color: orange;">p:inputText</span> specifies the required attribute. We can achieve the transformation of the <span style="color: orange;">@NotNull</span> annotation to the required attribute with the value <span style="color: orange;">true</span> if we set the context parameter <span style="color: orange;">primefaces.TRANSFORM_METADATA</span> to <span style="color: orange;">true</span>.
<br />
<br />
In the last step, all required JavaScript files have to be included on the page.
<br />
<pre class="brush:xhtml"><h:outputScript library="js" name="chapter10/lang_en.js"/>
<h:outputScript library="js" name="chapter10/validators.js"/>
</pre>
The next two pictures show what happens when validations fails<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-kbv35atLF8A/VKbavFNjTGI/AAAAAAAAAb8/SWe6Kg0R5cs/s1600/3427_10_04.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-kbv35atLF8A/VKbavFNjTGI/AAAAAAAAAb8/SWe6Kg0R5cs/s1600/3427_10_04.png" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-KG8FaulCu3M/VKbazZGkWfI/AAAAAAAAAcE/blqLvACn-70/s1600/3427_10_05.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-KG8FaulCu3M/VKbazZGkWfI/AAAAAAAAAcE/blqLvACn-70/s1600/3427_10_05.png" /></a></div>
If everything is ok, an alert box with the text Saved! is displayed to user.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-LPoxrt1qMdY/VKba_UohM7I/AAAAAAAAAcM/DCN29m1oW7A/s1600/3427_10_06.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-LPoxrt1qMdY/VKba_UohM7I/AAAAAAAAAcM/DCN29m1oW7A/s1600/3427_10_06.png" /></a></div>
<br />
<span style="font-family: Verdana,sans-serif;"><b>How it works...</b></span><br />
<br />
The message key <span style="color: orange;">invalid.cvc.message</span> and the text should be put in resource bundles named <span style="color: orange;">ValidationMessages</span>, e.g. <span style="color: orange;">ValidationMessages_en.properties</span>. <span style="color: orange;">ValidationMessages</span> is the standard name specified in the Bean Validation specification. The property files should be located in the application classpath and contain the following entry: <span style="color: orange;">invalid.cvc.message=Card Validation Code is invalid</span>. This configuration is important for the server-side validation.<br />
<br />
The method <span style="color: orange;">getMetadata()</span> in the class <span style="color: orange;">CvcClientConstraint</span> provides a map with name, value pairs. The metadata are exposed in the rendered HTML. The values can be accessed on the client-side via <span style="color: orange;">element.data(name)</span>, where element is an jQuery object for the underlying native HTML element. The CVC field with the metadata is rendered as
<br />
<pre class="brush:html"><input type="text" data-forcardmenu="@(.card)"
data-p-con="javax.faces.Integer" data-p-required="true"...>
</pre>
The most interesting part is the implementation of the client-side validator. The value to be validated is already numeric because first it gets converted by the PrimeFaces’ built-in client-side converter for the data type <span style="color: orange;">java.lang.Integer</span>. We only have to check if the value is positive and has a valid length. A valid length depends on the selected card in the menu <span style="color: orange;">p:selectOneMenu</span> that can be accessed by the PrimeFaces JavaScript API as <span style="color: orange;">PrimeFaces.expressions.SearchExpressionFacade.resolveComponentsAsSelector(selector)</span>, where selector is any PrimeFaces selector, in our case <span style="color: orange;">@(.card)</span>. If the validation fails, we throw an exception by invoking <span style="color: orange;">throw PrimeFaces.util.ValidationContext.getMessage(text, parameter)</span>.<br />
<br />
The client-side validation is triggered by setting <span style="color: orange;">validateClient=”true”</span> on the <span style="color: orange;">p:commandButton</span>.Oleg Varaksinhttp://www.blogger.com/profile/13872270134068047346noreply@blogger.com2tag:blogger.com,1999:blog-8492059842142356488.post-3283866967956609462014-12-08T22:17:00.002+01:002014-12-08T22:32:23.716+01:00Building dynamic responsive multi-level menus with plain HTML and OmniFacesRecently, I had to create a responsive multi-level menu with JSF 2.2. Requirements: the menu should<br />
<ul>
<li>be created with dynamic structure from backend</li>
<li>be responsive, i.e. desktop- and mobile-friendly</li>
<li>have submenu items with navigation links </li>
<li>support touch events</li>
<li>support keyboard accessibility</li>
</ul>
PrimeFaces' menus were not a choice. They can indeed be created programmatically by model, but<br />
<ul>
<li>they are not really responsive</li>
<li>submenu items only collapse / expand the submenus and can not contain navigation links</li>
<li>...</li>
</ul>
Well, why not to pick any jQuery based plugin for responsive multi-level menus? There are a lot of plugins. See <a href="http://exisweb.net/incredibly-useful-list-of-responsive-navigation-and-menu-patterns">Useful List of Responsive Navigation and Menu Patterns</a>. I choosen <a href="http://jasonweaver.name/lab/flexiblenavigation/">FlexNav</a>.<br />
<br />
But how to output the dynamic menu structure? <span style="color: orange;">ui:repeat</span> is not a choice here because the structure (nested sub menus, etc.) is not known a priori. Fortunately, there is OmniFaces with <a href="http://showcase.omnifaces.org/components/tree">o:tree</a>, which allows to have full control over the markup of a tree hierarchy by declaring the JSF components or HTML elements in the markup. <span style="color: orange;">o:tree</span> does not render any HTML markup by itself. Exactly what I need!<br />
<br />
I ended up with this XHTML fragment mixing <span style="color: orange;">o:treeNode</span>, <span style="color: orange;">o:treeNodeItem</span>, <span style="color: orange;">o:treeInsertChildren</span> and HTML elements defined by the mentioned FlexNav menu:
<br />
<pre class="brush:xhtml"><h:outputScript library="js" name="jquery.flexnav.js"/>
<h:outputStylesheet library="css" name="flexnav.css"/>
<ul id="mainnavi" class="flexnav" data-breakpoint="640" role="navigation">
<o:tree value="#{mainNavigationBean.treeModel}" var="item">
<o:treeNode level="0">
<o:treeNodeItem>
<li class="item">
<a href="#{item.href}" title="#{item.title}">#{item.text}</a>
<o:treeInsertChildren/>
</li>
</o:treeNodeItem>
</o:treeNode>
<o:treeNode>
<ul>
<o:treeNodeItem>
<li>
<a href="#{item.href}" title="#{item.title}">#{item.text}</a>
<o:treeInsertChildren/>
</li>
</o:treeNodeItem>
</ul>
</o:treeNode>
</o:tree>
</ul>
<h:outputScript id="mainnaviScript" target="body">
$(document).ready(function () {
$("#mainnavi").flexNav({'calcItemWidths': true});
});
</h:outputScript>
</pre>
The OmniFaces' <span style="color: orange;">TreeModel </span>with menu items is created programmatically. The Java code looks like
<br />
<pre class="brush:java">public TreeModel<NavigationItemDTO> getTreeModel() {
// get menu model from a remote service
NavigationContainerDTO rootContainer = remoteService.fetchMainNavigation(...);
TreeModel<NavigationItemDTO> treeModel = new ListTreeModel<>();
buildTreeModel(treeModel, rootContainer.getNavItem());
return treeModel;
}
private void buildTreeModel(TreeModel<NavigationItemDTO> treeModel, List<NavigationItemDTO> items) {
for (NavigationItemDTO item : items) {
buildTreeModel(treeModel.addChild(item), item.getNavItem());
}
}
</pre>
And the end result (desktop variant):<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-yNW3H__Q_48/VIYVT62NnSI/AAAAAAAAAbc/H5rzLNByjhQ/s1600/responsiveMenu.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-yNW3H__Q_48/VIYVT62NnSI/AAAAAAAAAbc/H5rzLNByjhQ/s1600/responsiveMenu.png" height="245" width="640" /></a></div>
<br />
Note that submenus are clickable and can be expanded on mouseover.<br />
<br />
You see, JSF is flexible and sometimes you don't need full-blown components. Have fun!Oleg Varaksinhttp://www.blogger.com/profile/13872270134068047346noreply@blogger.com6tag:blogger.com,1999:blog-8492059842142356488.post-20836617307623234932014-11-20T00:22:00.002+01:002014-11-20T00:24:30.925+01:00Don't repeat expressions in faceletsHave you ever seen repeated EL expressions in JSF like this one?
<br />
<pre class="brush:xhtml"><h:inputText value="#{oneBean.name}" rendered="#{anotherBean.showPerson}"/>
<h:inputText value="#{oneBean.birthday}" rendered="#{anotherBean.showPerson}"/>
<h:selectOneMenu value="#{oneBean.children}" style="#{anotherBean.showPerson ? 'display:block' : 'display:none'}"/>
</pre>
usw. Another example:
<br />
<pre class="brush:xhtml"><ui:include src="/include/somesnippet.xhtml">
<ui:param name="age" value="#{someBean.isMan(person) ? 63 : 60}"/>
<ui:param name="money" value="#{someBean.isMan(person) and someBean.getCountry(person) eq 'de' ? 1000 : 900}"/>
<ui:param name="big" value="#{someBean.getCountry(person) eq 'zh' or someBean.getCountry(person) eq 'ru' ? true : false}"/>
</ui:include>
</pre>
Expressions <span style="color: orange;">#{anotherBean.showPerson}</span>, <span style="color: orange;">#{someBean.isMan(person)}</span>, <span style="color: orange;">#{someBean.getCountry(person)}</span> are repeated multiple times. How to optimize them? Well, you can use JSTL's <span style="color: orange;">c:set</span> like this code snippet
<br />
<pre class="brush:xhtml"><c:set var="showPerson" value="#{anotherBean.showPerson}"/>
<h:inputText value="#{oneBean.name}" rendered="#{showPerson}"/>
<h:inputText value="#{oneBean.birthday}" rendered="#{showPerson}"/>
<h:selectOneMenu value="#{oneBean.children}" style="#{showPerson ? 'display:block' : 'display:none'}"/>
<c:set var="man" value="#{someBean.isMan(person)}"/>
<c:set var="country" value="#{someBean.getCountry(person)}"/>
<ui:include src="/include/somesnippet.xhtml">
<ui:param name="age" value="#{man ? 63 : 60}"/>
<ui:param name="money" value="#{man and country eq 'de' ? 1000 : 900}"/>
<ui:param name="big" value="#{country eq 'zh' or country eq 'ru' ? true : false}"/>
</ui:include>
</pre>
If you are scared about JSTL pitfalls (because you have heard that JSTL is not always JSF friendly :-)), there is an alternative and simple approach - <span style="color: orange;">ui:param</span>. TagHandler <span style="color: orange;">ui:param</span> uses JSF's <span style="color: orange;">VariableMapper</span> to save EL expressions in a map. This map maps EL variables on a page and the EL expressions they are associated with. And here you go:
<br />
<pre class="brush:xhtml"><ui:param name="showPerson" value="#{anotherBean.showPerson}"/>
<h:inputText value="#{oneBean.name}" rendered="#{showPerson}"/>
<h:inputText value="#{oneBean.birthday}" rendered="#{showPerson}"/>
<h:selectOneMenu value="#{oneBean.children}" style="#{showPerson ? 'display:block' : 'display:none'}"/>
<ui:param name="man" value="#{someBean.isMan(person)}"/>
<ui:param name="country" value="#{someBean.getCountry(person)}"/>
<ui:include src="/include/somesnippet.xhtml">
<ui:param name="age" value="#{man ? 63 : 60}"/>
<ui:param name="money" value="#{man and country eq 'de' ? 1000 : 900}"/>
<ui:param name="big" value="#{country eq 'zh' or country eq 'ru' ? true : false}"/>
</ui:include>
</pre>
The code is more readable, especially if you have very complex and long expressions. Note: we're speaking here about readable code and not about performance optimization because JSF TagHandlers don't evaluate EL expressions.
Oleg Varaksinhttp://www.blogger.com/profile/13872270134068047346noreply@blogger.com2tag:blogger.com,1999:blog-8492059842142356488.post-26871145543188090372014-11-07T00:20:00.002+01:002014-11-07T00:29:54.836+01:00Dynamic aria-live for better accessibility experienceEvery web developer working with the web accessibility (<a href="http://www.w3.org/TR/wai-aria/">WAI ARIA</a>) knows or heard about <span style="color: orange;">aria-live</span>. This is an attribute, which indicates a live region - any updatable HTML element - and describes the types of updates the user agents, assistive technologies (screen readers), and user can expect from the live region. The default value of the <span style="color: orange;">aria-live</span> is <span style="color: orange;">off</span>. That means, updates to the region will not be presented to the user unless the assistive technology is currently focused on that region. The value <span style="color: orange;">polite </span>means, assistive technologies should announce updates at the next graceful opportunity, such as at the end of speaking the current sentence or when the user pauses typing. There is also the value <span style="color: orange;">assertive</span>, which forces assistive technologies to notify the user immediately. In additional, the <span style="color: orange;">aria-relevant</span> attribute can specify if the updates on the live region should only be spoken when the corresponding DOM node is added or removed or both.<br />
<br />
Most time you need to set the value once and don't care about it. E.g. markup for error messages can contain <span style="color: orange;">aria-live="polite"</span>.
<br />
<pre class="brush:html"><div class="messages" aria-live="polite">
... some messages ...
</div>
</pre>
Every time when the content of the <span style="color: orange;">div</span> container with <span style="color: orange;">class="messages"</span> is updated, it will be spoken by screen readers. That's good, but sometimes you only would like to notify a sightless user when the new (after update) and old (before update) contents are not equal. Imagine a railway ticket shop where users can choose fare class, number of traveler, book places, etc. The total buy price is permanently updated. We can write
<br />
<pre class="brush:html"><span aria-live="polite">
<div id="pricetotal">
<span class="hiddenOfScreen">Total price </span>
#{price}
</div>
</span>
</pre>
and update the <span style="color: orange;">div</span> by AJAX. <span style="color: orange;">#{price}</span> is a current price as EL expression calculated on the server-side (coming from the JSF world, but JavaScript templating has similar expressions). Whenever the <span style="color: orange;">div </span>gets updated, screen readers speak the total price regardless if the amount was changed or not. A more clever approach sets <span style="color: orange;">aria-live</span> dynamically at runtime. If the amount was changed, the <span style="color: orange;">aria-live</span> on the <span style="color: orange;">div</span> should have the value <span style="color: orange;">polite</span>. If the old and new prices are equal, the <span style="color: orange;">div</span> should have the value <span style="color: orange;">off</span>. The <span style="color: orange;">off </span>value prevents speaking by screen readers.<br />
<br />
The idea is to save the last updated price in the <span style="color: orange;">data-price</span> attribute of the parent element and compare the old and new prices on every AJAX update. In the code snippet below, the <span style="color: orange;">div</span> with <span style="color: orange;">id="pricetotal"</span> gets updated. The JavaScript block inside is being executed on every update. We read and compare old and new prices and manipulate the <span style="color: orange;">aria-live</span> attribute at runtime. Whenever the <span style="color: orange;">aria-live</span> is set to <span style="color: orange;">polite</span>, screen readers speak "Total price" and the amount.
<br />
<pre class="brush:html"><span data-price="#{price}">
<div id="pricetotal">
<span class="hiddenOfScreen">Total price </span>
<span class="priceoutput">#{price}</span>
<script type="text/javascript">
$(document).ready(function () {
$pricetotal = $('#pricetotal');
var oldPrice = $pricetotal.parent().data('price');
var newPrice = $pricetotal.find('.priceoutput').text();
if (oldPrice != newPrice) {
$pricetotal.attr('aria-live', 'polite');
$pricetotal.parent().data('price', newPrice);
} else {
$pricetotal.attr('aria-live', 'off');
}
});
</script>
</div>
</span>
</pre>
If prices are not equal, the new price is saved in the <span style="color: orange;">data-price</span> to make it available in the next update.Oleg Varaksinhttp://www.blogger.com/profile/13872270134068047346noreply@blogger.com0tag:blogger.com,1999:blog-8492059842142356488.post-9650996581892422722014-11-03T00:54:00.002+01:002014-11-03T00:54:26.168+01:00PrimeFaces Extensions 3.0.0 releasedToday, we released the <a href="http://primefaces-extensions.github.io/">PrimeFaces Extensions</a> 3.0.0. It is built on top of <a href="http://www.primefaces.org/">PrimeFaces</a> 5.1 and is fully compatible with PrimeFaces 5.1.x.<br />
<br />
There are new components: <span style="color: orange;">pe:countDown</span>, <span style="color: orange;">pe:knob</span>, <span style="color: orange;">pe:gravatar</span>, <span style="color: orange;">pe:documentViewer</span>, <span style="color: orange;">pe:analogClock</span>, <span style="color: orange;">pe:gChart</span>. I have <a href="http://ovaraksin.blogspot.de/2014/09/brand-new-jsf-components-in-primefaces.html">blogged</a> about them.<br /><br />The new deployet showcase will be available soon as usually <a href="http://www.primefaces.org/showcase-ext/views/home.jsf">here</a>. The next release will be a maintenance release. It is time for bugfixing.<br />
<br />
Have fun!Oleg Varaksinhttp://www.blogger.com/profile/13872270134068047346noreply@blogger.com0