Developers want evermore speedy ways to complete their applications. Many want to use familiar languages and concepts like JavaScript, JSON, CSS and XHTML. In this post I show how you can quickly integrate my MLDB JavaScript API wrapper in to your own Roxy web application without learning any XQuery. I’ll show how to create a search page, and load JSON documents in to MarkLogic. I have both a video with instructional audio, and written instructions for those that need them. Read on for more…
Pre-requisites
You need to follow the first tutorial on creating a shell hybrid Roxy and REST API application. This tutorial follows on from that.
BEFORE YOU START CODING: The full src directory for the application, and code Gists, are available via links from the bottom of this article.
YouTube video version
Text version
Below is the full list of items covered in the video above. Just incase you’re on a train or can’t understand my crazy British accent!
Creating a new Roxy controller and view
Run the following command to create a new controller with a main function, and a html web view.
./ml create search html
Type ‘yes’ and hit enter when asked
Copy in custom layout and CSS
Roxy follows the same conventions as the MarkLogic application builder – that is, it assumes every application you create will have a search bar on every page. This is coded in to the layout so that page developers don’t need to do anything. We though need to embed our search widget on a single page in the application, and so we need a custom layout that doesn’t show the search bar in the header. The ones linked below and their CSS (the ‘less’ file) do this for you, so you don’t need to learn Roxy layouts at this stage. (Something to take a look at if, like with me, insomnia strikes!)
Copy the one-column.html.xqy file to src/app/views/layouts
Copy the one-column.less file to src/public/css
The widgets I’ve provided as part of MLDB are designed so you can easily use CSS to apply any styling or layout you want. This flexibility is good, but does mean casual users would find it tricky to get started with a good looking layout. To help this along, I’ve also included class links for the 960.css grid layout. This is a fantastic approach to CSS I highly recommend. It means I don’t need to understand how interactions happen between containers and elements, I just need to use the appropriate class definition.
For this exercise, we’ll just use the 960.css. You’ll need to download this from here: http://960.gs (Click the Big ol’ download button!)
Unzip this file and place the 960 folder in full under src/public/css
Edit the search controller to use our new layout
If using TextMate a mac, type ‘mate .’ in the command line. This opens a file view with folder so you can browse an entire application.
Edit the src/app/controllers/search.xqy file
Replace your main() function with the below. This instructs Roxy to use the one-column layout for this page’s rendering in (x)html.
declare function c:main() as item()* { ch:add-value("message", "This is a test message."), ch:add-value("title", "Search"), ch:use-view((), "xml"), ch:use-layout("one-column", "html") };
Edit the search main view to link to our widgets
You could add the relevant CSS and JavaScript files to the layout, but I’m assuming you’re writing a large application where you don’t want to load everything in to the browser for every page, ‘just in case’. Also because I want to show you what pieces you need for each part of the application.
Edit the src/app/views/search/main.html.xqy file. Replace the contents of the div tag (not the div tag itself) with this Gist. (01-main.html)
There are a few obvious files in here. Firstly, the mldb.js driver code itself. Then widgets.css (the default classes) and widgets.js files (widget baseline code). Also the widget-search JavaScript file which contains all search widgets (currently 7 of them – searchbar, facets, pager, sorter, results, search page, co-occurence).
There’s also a less obvious page-search.js. I like putting ALL JavaScript in external files. XQuery files dislike { and } characters as they’re inline code indicators. Also, using an external file keeps your code neat, and should be done as best practice. </lecture>
The last odd reference is the mldb-jquery.js file. I had many options to use as transport wrappers for AJAX calls that work cross browser. I’ve shipped three. jQuery (which Roxy layouts all include links to, and is shipped with Roxy), Prototype.js (which is a favourite library of mine) and xhr which attempts to user browsers’ own XmlHttpRequest objects. The jQuery one has received most testing as it makes the most sense with Roxy applications. Feel free to switch for mldb-prototype.js or mldb-xhr.js too, if you like. (And if / when they don’t work, add the problem and JavaScript console output to my Issues Tracker for MLDB)
Install MLDB in to your application
Go and fetch the latest mldb-browser.tar.gz or mldb-browser.zip file and unzip it directly in to your src/public folder (this should copy css in to /src/public/css and javascript in to /src/public/js folders)
Done! 8o) Easy huh?
Linking it all together
Now we need to link our HTML div tag container to an instance of our search page widget. We do this by creating the /src/public/js/page-search-main.js file:-
$(document).ready(function() { var db = new mldb(); var wgt = new com.marklogic.widgets.searchpage("search-content"); var ob = db.options(); ob.collectionConstraint(); var options = ob.toJson(); wgt.setOptions("mldbtest-page-search-options",options); wgt.execute(); });
The above code creates an MLDB instance (which auto links to the REST server this app is deployed into), adds a new search widgets, and configures it’s options so that it includes a facet constant and some sensible defaults (10 results per page, returned as full JSON documents). We also execute the empty search (return all docs the user has permissions to see).
Deploying the application
You will have already done a full bootstrap and deploy in the previous tutorial, so now you just need to deploy the app again. Type this in the command terminal:-
./ml local deploy modules
Now navigate your browser to: http://localhost:8101/search
If all has gone well, after a second or so you should see a well laid out search page, with facets (‘browse’) area on the left, and a search bar on the right with search paging, sorting and results areas below it. Type anything and click ‘search’. You’ll notice it works, but no results are returned.
Add some sample content
Now we’ll prove it works by adding some sample content. You can just upload these in to MarkLogic, but its much more fun (and a learning experience!) to do this via MLDB and JavaScript!
Create a new load method in your controller, with an associate load.html.xqy view:-
./ml create search/load html
Again, edit the /src/app/controllers/search.xqy file so it’s load() method looks like this:-
declare function c:load() as item()* { ch:add-value("message", "This is a test message."), ch:add-value("title", "Load"), ch:use-view((), "xml"), ch:use-layout("one-column", "html") };
Now edit the /src/app/views/search/load.html.xqy file, and replace it’s div tag and contents with this Gist (04-load.html).
Create /src/public/js/page-search-load.js so it contains this:-
$(document).ready(function() { var db = new mldb(); var docs = [ {title: "The Goonies",actor: "Sean Astin", genre: "Comedy", year: "1985"}, {title: "50 First Dates",actor: "Sean Astin", genre: "Comedy", year: "2004"}, {title: "Kingdom Hearts",actor: "Sean Astin", genre: "Comedy", year: "2002"}, {title: "The Sky Is Falling",actor: "Sean Astin", genre: "Comedy", year: "2001"}, {title: "Dorothy and the Witches of Oz",actor: "Sean Astin", genre: "Fantasy", year: "2012"}, {title: "The Lord of the Rings: The Return of the King",actor: "Sean Astin", genre: "Fantasy", year: "2003"}, {title: "The Lord of the Rings: The Two Towers",actor: "Sean Astin", genre: "Fantasy", year: "2002"}, {title: "The Lord of the Rings: The Fellowship of the Ring",actor: "Sean Astin", genre: "Fantasy", year: "2001"}, {title: "Teenage Mutant Ninja Turtles",actor: "Sean Astin", genre: "Adventure", year: "2013"}, {title: "Dumb and Dumber To",actor: "Jim Carrey", genre: "Comedy", year: "2014"}, {title: "Kick-Ass 2",actor: "Jim Carrey", genre: "Comedy", year: "2013"}, {title: "Mr. Popper's Penguins",actor: "Jim Carrey", genre: "Comedy", year: "2011"}, {title: "I Love You Philip Morris",actor: "Jim Carrey", genre: "Comedy", year: "2009"}, {title: "Ace Ventura: When Nature Calls",actor: "Jim Carrey", genre: "Comedy", year: "1995"}, {title: "Ace Ventura: Pet Detective",actor: "Jim Carrey", genre: "Comedy", year: "1994"}, {title: "A Christmas Carol",actor: "Jim Carrey", genre: "Drama", year: "2009"}, {title: "The Number 23",actor: "Jim Carrey", genre: "Drama", year: "2007"} ]; for (var i = 0;i < docs.length;i++) { db.save(docs[i],"/movies/" + i,{collection: "movies"}, function(result) { // do nothing - assume it works }); } });
Save all the files, then redeploy using this:-
./ml local deploy modules
Now visit this page, and wait 15 seconds (so the underlying javascript completes). You will see no confirmation message. http://localhost:8101/search/load
When done, visit the search page again: http://localhost:8101/search
You should see results in the search page. Voila! Not so difficult is it?
Type in ‘drama’ and click search – you see only two results. Even with no specific search indexes, full text search using the universal index still works and enables you to find all relevant information.
Next steps
At the moment the search results show the XML or JSON content (depending on what the document contains). In most cases you’ll want to customise these results. You’ll also want to define constraints and facets to control the search, and sort options. I cover all this in my next blog entry…
Files
You can access the final complete application here: [tar.gz via SugarSync public link]
The Gists for this application are contained here: [Gist website]
One comment