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 info.magnolia.module.jsmodels.rendering.JavascriptRenderingModel (required)
  • 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



Those classes allow invoking of methods and property access on our JavaScript objects.  We can limit this behavior in a couple of ways:



Example


add this to your webapp pom
<dependency>
  <groupId>info.magnolia.javascript-models</groupId>
  <artifactId>magnolia-module-javascript-models</artifactId>
  <version>1.0-SNAPSHOT</version>
</dependency>

If you are using M 5.6.*, try this instead:

<dependency>
  <groupId>info.magnolia.javascript-models</groupId>
  <artifactId>magnolia-module-javascript-models</artifactId>
  <version>1.1.1</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.




new-module/templates/components/contacts.yaml
templateScript: /new-module/templates/components/contacts.ftl
renderType: freemarker
modelClass: info.magnolia.module.jsmodels.rendering.JavascriptRenderingModel




new-module/templates/components/contacts.ftl
[#assign allContacts = model.getContacts()]
 
<ul>
[#list allContacts as contact]
    <li>${model.format(contact)}</li>
[/#list]
</ul>




new-module/templates/components/contacts.js
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();



add this to the availableComponents of some area definition
      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.





  • No labels