Patterns for Roxy and CRUD applications…

This document describes the patterns I’ve employed when building demonstration systems on Roxy for MarkLogic 6. Many could be taken for other XQuery servers or even different programming languages altogether. Most will be familiar to Ruby on Rails developers as they are effectively similar paradigms.

This document is purely a placeholder for my though processes at the moment and is not intended as a how to. Hopefully just viewing the ideas below will be useful. If you are interested in the full result please email me at adam.fowler@marklogic.com

Note on formatting – anywhere you see colons – E.g. :json: – means that value is replaced with the value within the variable. E.g. #:entity:-:elid: may resolve to #report-1234.

CRUD framework

JavaScript framework and Roxy controller conventions to support quick AJAX interaction with a Roxy controller. Build your Controllers to match the below URL conventions, then just include the JavaScript library to use them.

CRUD.menu(entity,elid) – invokes GET /:entity:/menu.htf to render HTML fragment of actions available over all :entity:. E.g. Create new, list. Renders content in to $(:elid:)
CRUD.new(entity) – invokes GET /:entity:/new.htf to render HTML fragment of form to create a new instance of :entity:. Renders content in to $(#:entity:-new-a)
CRUD.create(entity) – invokes POST /:entity:/create.json to create new :entity: instance. Extracts uri parameter from returned json, if successful, or shows error message at
top of ‘new’ form. Immediately calls CRUD.edit(entity,uri,”new”) on successful completion. Note this function automatically trawls through all form fields within $(#:entity:-new)
and passes them as POST parameters to the controller. This removes any logic you need to add AJAX to your forms. 8o) You’re welcome.
CRUD.edit(entity,uri,elid) – invokes GET /:entity:/edit.htf?uri=:uri: to render HTML fragment of edit form. Renders content in to $(#:entity:-:elid:)
CRUD.addElementRef(entity,element,entityuri,refuri,jsonparams) – invokes POST /:entity:/add:element:.json passing in entityuri and refuri parameters, plus any custom ones in :jsonparams:
This function does not trawl through any form fields. It is anticipated this will be used to link existing document URIs to your entity instance. In the future I may add a form
compatible version too.
CRUD.show(entity,uri,elreplace) – invokes GET /:entity:/show.htf?uri=:uri: to render a HTML fragment for the entity instance. Renders content in to $(#:elreplace:)
CRUD.delete(entity,uri) – invokes POST /:entity:/delete.json?uri=:uri: to delete an entire entity

Coming soon…

CRUD.addElement(entity,uri,elform)
CRUD.showElements(entity,element,entityuri,elinsertinto) – render e.g. senders within $(#message-senders) container
CRUD.list(entity,jsonparams)
CRUD.search(entity,query,elreplace)
CRUD.deleteElementRef(entity,element,entityuri,refuri)
CRUD.create – allow extra parameter after: edit,show to determine order of preference as to attempted functions after create succeeds.
If any are not present, do not show error. (Show ‘success’ in form instead)

Process for using CRUD capabilities to an application

  1. Create a controller for your entity – ./ml create message/show htf
  2. Add methods for each CRUD method you wish to support – ./ml create message/new htf ; ./ml create message/create json
  3. Edit new.htf to have a form with AJAX JavaScript overrides – <form id=”message-new” … onsubmit=”return false”> <!– form fields here –><input type=”submit” … onclick=”CRUD.create(‘message’);”/></form>
    Note the return false on the form element. This stops the form being submitted in addition to the AJAX call being performed.
  4. In message.xqy controller’s create function, add XQuery to perform the relevant xdmp:document-insert. Pass new docuri via ch:add-value to your create.json
  5. Edit create.json to return any error message within the error parameter, and new doc uri within the uri parameters in the JSON
  6. Edit your layout to include /js/CRUD.js
  7. Edit a page to show a link to ‘New Message’ – <div id=”message-new-a”><a href=”#” onclick=”CRUD.new(‘message’);return false;”>New Message</a></div>
  8. Edit message.xqy’s show function to load the entity instance at fn:doc(uri)
  9. Edit show.htf to render the selected instance as read only html
  10. Deploy app again using ./ml local deploy modules or similar

Note that you can even embed the above new link within a search page. This is useful if you’re creating new content based on existing content. See CRUD.show and CRUD.showElements for details of rendering content within a search page. Useful if you navigate between pages but want the same entity to be loaded within the page. You’ll need to use xdmp:set-session-field to save a reference to the ‘current’ entity that you want loaded, and have the search html page make a call to CRUD.show or CRUD.edit as applicable.

Process for supporting Drag and Drop editing
– depends upon CRUD library

Create a hidden form element within the root of each representation of an entity in your web application. This will contain a URL encoded string as its value for the doc URI (or other internal ID in your app).

DND.link(entity,element,elinsertinto) – sets up all jQuery draggable and droppable and calls to CRUD.addElement. Requires target element has class .entity and id
#elinsertinto (required???) and contains a hidden input field with class .appid that holds the URI of the entity. Also requires draggables to have class .element.
Only needs to be called once for entire page. Add following to your page: <script type=”text/javascript”>$(document).ready(function() {{DND.link(‘message’,’sender’,’senders’);}});</script>

Note the double {{ and }} escaping if the HTML is used within an XQuery module.

Adding AJAX search to a Roxy application

This provides the functionality of search-lib and facets-lib as its own controller to allow flexible AJAX searching and rendering. It includes a controller for the /searchajax/ URL that can perform most built in MarkLogic search functionality, and can be extended without code modifications to the library in order to support your own search facets, indexes, and result rendering capabilities. The aim of this is to make the search rendering appear speedy, just like the actual search time within MarkLogic 6 Server. In demos on a laptop the search can take 0.003 seconds, but rendering the page takes several seconds due to no browser caching. Using this AJAX library avoids this problem.

SearchAJAX variables – 5 globals: SearchAJAX.eForm = “searchform”,eSummary = “search-result-bar”,eFacets = “searchfacets”,eResults = “searchresults”,controllerPrefix = “/”;
SearchAJAX.init – loads the search page using AJAX by calling SearchAJAX.loadSearchForm,loadSummary,loadResults,loadFacets. Call this once when your page initially loads
SearchAJAX.loadSearchForm – invokes GET /searchajax/basicsearch.htf and renders content within SearchAJAX.eForm
SearchAJAX.loadSummary – invokes GET /searchajax/summary.htf and renders content within SearchAJAX.eSummary
SearchAJAX.loadResults(query) – invokes GET /searchajax/search.htf?q=:query: and renders content within SearchAJAX.eResults. Controller method stored search query and results in the session.
Also calls loadSummary and loadFacets after search results are returned
SearchAJAX.loadFacets – invokes GET /searchajax/facets.htf and renders content within SearchAJAX.eFacets
SearchAJAX.performSearch – designed to be called from a basic search form. Extracts query from $(#basicquery).attr(value) and calls SearchAJAX.loadResults

Coming soon…

SearchAJAX.loadSearchForm – add parameter options json that takes an array of supported search types. E.g. basic (single input field), advanced (full text and query builder), geospatial (map),
and config parameters for each of these options. E.g. default location and zoom, or extra field config to show within advanced search area
SearchAJAX.init – limit search results to a particular collection or root node (E.g. m:message)
SearchAJAX.loadSimilar – invokes GET /searchajax/similar.htf to render related search results to the one selected (invokes a cts:similar)
SearchAJAX.performGeoSearch
SearchAJAX.performAdvancedSearch

SearchAJAX.saveToWorkbench(query)
SearchAJAX.loadWorkbench(elinsert)
SearchAJAX.addUserAlert(query)

Note the $CONFIG:search-entities configuration option should be used to customise results display. The search controller and libraries will use xdmp:eval to call the relevant rendering helpers. facets.htf uses sh:facets (not Roxy facet-lib) to render facets in a sidebar. This makes uses of Roxy facet names where configured. summary.htf renders pagination links and sort by options. Alternative sort bys can be configured in $CONFIG:search-sortby. Defaults are relevance, newest, oldest. Alters the sort: option

Note also that the /searchajax/main.html endpoint renders the full search page if you don’t want to construct your own.

Advertisements

One comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s