Using Angular with Roxy

Author: Dave Cassel  |  Category: Software Development

On a few different people’s recommendations, I’ve been looking at AngularJS lately. Something I ran into early was the expectation that you use HTML5, which is generally not valid XML (meta and link elements aren’t closed, and AngularJS uses some valueless directives, like <body ng-app>). MarkLogic also gets confused by the {{ }} binding markers in a file it thinks might be XQuery. That means we need to store the HTML as text in MarkLogic, which is fine if you’re using straight-up HTML, but what about with XQuery-based views & layouts?

Looking into using Angular with Roxy‘s MVC application structure, I find myself leaning toward using the MVC approach to build services and defer nearly the entire UI to JavaScript on the front-end. So how do we do that in a Roxy MVC project?

Here are the steps I came up with.

  1. Create src/public/html/
  2. Create one or more .html files in that directory
  3. Instruct the Roxy deployer to load HTML files as text
  4. Add rules to the rewriter so that the HTML files are accessible

The first two steps are pretty self explanatory. To tell Roxy to load HTML files as text, we copy the load-html-as-xml property from deploy/default.properties to deploy/build.properties:

load-html-as-xml=false

Now let work on the rewriter. We’re going to add two rules. One will take any request that ends with .html and direct it to the public/html directory:

<request uri="^/(.*html)" endpoint="/public/html/$1"/>

Note that this has the effect of masking requests to MVC endpoints using the html format. With this approach, we’re committed! (Note on an alternative approach below.)

We should also set a default home page. Normally, Roxy MVC defaults to /<default-controller>/<default-function>.<default-format>, for instance, /appbuilder/main.html. We’re going to set it to an html page:

<request uri="^/$" endpoint="/public/html/index.html"/>

… assuming that we have created an index.html. With these changes, here’s how $c:ROXY-ROUTES in src/app/config/config.xqy looks:

declare variable $c:ROXY-ROUTES :=
  <routes xmlns="http://marklogic.com/appservices/rest">
    <request uri="^/$" endpoint="/public/html/index.html"/>
    <request uri="^/(.*html)" endpoint="/public/html/$1"/>
    {
      $def:ROXY-ROUTES/rest:request
    }
  </routes>;

Another helpful step we can take is to choose a default format other than HTML. We can do so in src/app/config/config.xqy, changing $c:ROXY-OPTIONS:

declare variable $c:ROXY-OPTIONS :=
  <options>
    <default-format>json</default-format>
    <layouts>
      <layout format="html">three-column</layout>
    </layouts>
  </options>;

This means that when a client hits an endpoint with no format specified, like /users/profile, it will be assume a json response format instead of html. Clients can explicitly specify this as /users/profile.json, as usual.

Alternative Approach

As mentioned above, this approach masks MVC endpoint requests with the HTML format. For instance, if we ask for /search/main.html, the rewrite rules above will redirect to /public/html/search/main.html, rather than the search controller’s main function. I’m okay with that, because I want to use Angular to build my UI on top of an HTML template. Here are two other approaches you can use, if you want to keep the ability to hit HTML endpoints.

Use the default format

The routing path above rewrites any path that ends in html to the static html directory. However, if we leave the default-format option with the original html, then we can still use a traditional view/template by using a path like /user/add-form and get back an HTML page.

More specific route path

The routing path above is pretty course: if it ends in html, it’s rewritten to /public/html/. We could also be more specific, like requiring paths to HTML to have a longer path, like /html/user-form.html. Then the path in $c:ROXY-ROUTES could be uri=”^/html/(.*)$” endpoint=”/public/html/$1″. Personally, I don’t like the URLs you get from this approach.

AngularJS and the REST API

If you’re doing a Roxy application with app-type=rest, then the HTML part of this is easy: that kind of application expects HTML files. You’ll still need to tell Roxy not to load them as XML. From that point, the trick is to get Angular to work with the REST API. I haven’t done that yet, but if I do, you’ll see it here.

Tags: , , , ,

2 Responses to “Using Angular with Roxy”

  1. George Everitt Says:

    Thanks for writing this, David. We were kind of torn on how to start introducing AngularJS into Epinomy, and these suggestions will help quite a bit.

  2. Dave Cassel Says:

    Hi George. Take a look at the MarkLogic/Node Slush generator for a faster starting point: https://github.com/marklogic/slush-marklogic-node. Personally I’ve switched over to a 3-tiered setup with Node.js in the middle, talking to MarkLogic through the REST API.

Leave a Reply