The Java 8 release included a JavaScript engine called Nashorn. Nashorn allows us to run dynamic JavaScript code natively on the JVM.
Prerequisites
- Java 8
- Magnolia 5.5+
What you need to do
- in your YAML template:
modelClass
property pointing to
(required)info.magnolia.module.jsmodels.rendering.JavascriptRenderingModel
- in your YAML template:
modelPath
property pointing to where you have stored the JavaScript code (optional - useful for model re-use among different templates). If you don't do this, the system will look for a file with the same name as your template, only with a.js
extension.
What Magnolia provides
- info.magnolia.module.jsmodels.model.JavascriptModel
- info.magnolia.module.jsmodels.model.JavascriptFunctionModel
Those classes allow invoking of methods and property access on our JavaScript objects. We can limit this behavior in a couple of ways:
Example
<dependency> <groupId>info.magnolia.javascript-models</groupId> <artifactId>magnolia-module-javascript-models</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
If your bundle doesn't already include it, and if you are unable to include this, the jar file is attached: magnolia-module-javascript-models-1.0.jar Simply drop it in your author instance WEB-INF/lib and restart Magnolia. Otherwise, you could download it from here.
templateScript: /new-module/templates/components/contacts.ftl renderType: freemarker modelClass: info.magnolia.module.jsmodels.rendering.JavascriptRenderingModel
[#assign allContacts = model.getContacts()] <ul> [#list allContacts as contact] <li>${model.format(contact)}</li> [/#list] </ul>
var MyModel = function () { this.getContacts = function () { var result = new Array(); var nodes = ctx.getJCRSession("contacts").getRootNode().getNodes(); while (nodes.hasNext()) { node = nodes.next(); if (node.getPrimaryNodeType().getName() == 'mgnl:contact') { result.push(node); } } return result; }; this.format = function (contact) { return contact.getProperty("firstName").getString() + ' ' + contact.getProperty("lastName").getString(); }; }; new MyModel();
contacts: id: new-module:components/contacts
The result
Nashorn - Pros and Cons
Pros:
- No need to know Java to implement models
May inject and use any Java class into the JavasScript model
- Front-end developers may load external libraries in their model and use them (see load function here)
- The models work immediately (no need to compile/restart/etc) - they use Magnolia's resource-loader API
Cons:
- Front-end developers will need Javadoc for Node APIs
- Model inheritance is not possible in JavaScript
- Maybe JavaScript models are slower than Java models
This page originally adapted from here.
The main Magnolia documentation for this topic is JavaScript Models module.
Some more examples may be found here.