At the last MIX conference, Netflix announced that they are exposing their catalog of movie information using the OData protocol. This is great news! This means that you can take advantage of all of the advanced OData querying features against a live database of Netflix movies.
In this blog entry, I’ll demonstrate how you can use Netflix, jQuery, JSONP, and OData to create a simple movie lookup form. The form enables you to enter a movie title, or part of a movie title, and display a list of matching movies. For example, Figure 1 illustrates the movies displayed when you enter the value robot into the lookup form.
Using the Netflix OData Catalog API
You can learn about the Netflix OData Catalog API at the following website:
The nice thing about this website is that it provides plenty of samples. It also has a good general reference for OData. For example, the website includes a list of OData filter operators and functions.
The Netflix Catalog API exposes 4 top-level resources:
- Titles – A database of Movie information including interesting movie properties such as synopsis, BoxArt, and Cast.
- People – A database of people information including interesting information such as Awards, TitlesDirected, and TitlesActedIn.
- Languages – Enables you to get title information in different languages.
- Genres – Enables you to get title information for specific movie genres.
OData is REST based. This means that you can perform queries by putting together the right URL.
For example, if you want to get a list of the movies that were released after 2010 and that had an average rating greater than 4 then you can enter the following URL in the address bar of your browser:
http://odata.netflix.com/Catalog/Titles?$filter=ReleaseYear gt 2010&AverageRating gt 4
Entering this URL returns the movies in Figure 2.
Creating the Movie Lookup Form
The complete code for the Movie Lookup form is contained in Listing 1.
Listing 1 – MovieLookup.htm
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Netflix with jQuery</title> <style type="text/css"> #movieTemplateContainer div { width:400px; padding: 10px; margin: 10px; border: black solid 1px; } </style> <script src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.2.js" type="text/javascript"></script> <script src="App_Scripts/Microtemplates.js" type="text/javascript"></script> </head> <body> <label>Search Movies:</label> <input id="movieName" size="50" /> <button id="btnLookup">Lookup</button> <div id="movieTemplateContainer"></div> <script id="movieTemplate" type="text/html"> <div> <img src="<%=BoxArtSmallUrl %>" /> <strong><%=Name%></strong> <p> <%=Synopsis %> </p> </div> </script> <script type="text/javascript"> $("#btnLookup").click(function () { // Build OData query var movieName = $("#movieName").val(); var query = "http://odata.netflix.com/Catalog" // netflix base url + "/Titles" // top-level resource + "?$filter=substringof('" + escape(movieName) + "',Name)" // filter by movie name + "&$callback=callback" // jsonp request + "&$format=json"; // json request // Make JSONP call to Netflix $.ajax({ dataType: "jsonp", url: query, jsonpCallback: "callback", success: callback }); }); function callback(result) { // unwrap result var movies = result["d"]["results"]; // show movies in template var showMovie = tmpl("movieTemplate"); var html = ""; for (var i = 0; i < movies.length; i++) { // flatten movie movies[i].BoxArtSmallUrl = movies[i].BoxArt.SmallUrl; // render with template html += showMovie(movies[i]); } $("#movieTemplateContainer").html(html); } </script> </body> </html>
The HTML page in Listing 1 includes two JavaScript libraries:
<script src=”http://ajax.microsoft.com/ajax/jquery/jquery-1.4.2.js” type=”text/javascript”></script>
<script src=”App_Scripts/Microtemplates.js” type=”text/javascript”></script>
The first script tag retrieves jQuery from the Microsoft Ajax CDN. You can learn more about the Microsoft Ajax CDN by visiting the following website:
The second script tag is used to reference Resig’s micro-templating library. Because I want to use a template to display each movie, I need this library:
When you enter a value into the Search Movies input field and click the button, the following JavaScript code is executed:
// Build OData query var movieName = $("#movieName").val(); var query = "http://odata.netflix.com/Catalog" // netflix base url + "/Titles" // top-level resource + "?$filter=substringof('" + escape(movieName) + "',Name)" // filter by movie name + "&$callback=callback" // jsonp request + "&$format=json"; // json request // Make JSONP call to Netflix $.ajax({ dataType: "jsonp", url: query, jsonpCallback: "callback", success: callback });
This code Is used to build a query that will be executed against the Netflix Catalog API. For example, if you enter the search phrase King Kong then the following URL is created:
This query includes the following parameters:
- $filter – You assign a filter expression to this parameter to filter the movie results.
- $callback – You assign the name of a JavaScript callback method to this parameter. OData calls this method to return the movie results.
- $format – you assign either the value json or xml to this parameter to specify how the format of the movie results.
Notice that all of the OData parameters — $filter, $callback, $format — start with a dollar sign $.
The Movie Lookup form uses JSONP to retrieve data across the Internet. Because WCF Data Services supports JSONP, and Netflix uses WCF Data Services to expose movies using the OData protocol, you can use JSONP when interacting with the Netflix Catalog API. To learn more about using JSONP with OData, see Pablo Castro’s blog:
The actual JSONP call is performed by calling the $.ajax() method. When this call successfully completes, the JavaScript callback() method is called.
The callback() method looks like this:
function callback(result) { // unwrap result var movies = result["d"]["results"]; // show movies in template var showMovie = tmpl("movieTemplate"); var html = ""; for (var i = 0; i < movies.length; i++) { // flatten movie movies[i].BoxArtSmallUrl = movies[i].BoxArt.SmallUrl; // render with template html += showMovie(movies[i]); } $("#movieTemplateContainer").html(html); }
The movie results from Netflix are passed to the callback method. The callback method takes advantage of Resig’s micro-templating library to display each of the movie results. A template used to display each movie is passed to the tmpl() method. The movie template looks like this:
<script id="movieTemplate" type="text/html"> <div> <img src="<%=BoxArtSmallUrl %>" /> <strong><%=Name%></strong> <p> <%=Synopsis %> </p> </div> </script>
This template looks like a server-side ASP.NET template. However, the template is rendered in the client (browser) instead of the server.
Summary
The goal of this blog entry was to demonstrate how well jQuery works with OData. We managed to use a number of interesting open-source libraries and open protocols while building the Movie Lookup form including jQuery, JSONP, JSON, and OData.
this templating is not good.
suppose we want to create very simple template in which there are 2 items -place holder to display name, a button to show/hide name. Now for this functionality. we have to bind methods to target element every time binding occurs.
–while an ideal template should be pure html and with all events bound to it.
–binding should be done like below
$(‘#targetElm’).bindJson(‘templateId’,data);
–now target will have filed templates with no need to bound events again to them.
this way once created template can be reused again and again. this way we can do things like create an accordion template and recreate new accordion just by binding with new data and so on.
Stephen, can you check the line 49 of the listing 1. There is something that might be awkward:
+ “&$callbackcallback=callback” // jsonp request
Regards,
R.
@Roland — thanks! That appears to be a bug in the syntax highlighter that causes callback to appear twice, the code should be:
+ “&$callback=callback” // jsonp request
This line of code is critical because it tells the WCF Data Service to support JSONP (otherwise, you’ll get a missing : exception in IE or an invalid label exception from the Firefox).
@Praveen This is just a small sample application, and is great for getting a start.
The more customizable functionality described is saved for you to do yourself 🙂
Thanks Stephen for this post! 🙂
Put Scripts at Bottom:
I’ve commented on this topic before…
But one should really as a evangelist try to use best practice (as people tend to use code showed as presented)
Therefore it is of IMPORTANCE that you (and other) when displaying javascript demos follow best practice.
Place javascript includes
developer.yahoo.com/…/rules.html#js_bottom
Ease up JonW, scripts should be at the bottom agreed, but in the example it has no relevance, there would be extremely little advantage to doing so.
Mark
I tend to stongly disagree with you.
1) People tend to use code showed AS presented.
Even in this simple demo one could easily follow that simple best practice and pherhaps Kill two birds with one stone
And complete with,
2) there is absolutly NO ADVANTAGE in placing the script in the head section, so why do it in the 1:st place?
You have prearranged outstanding inspiration here.
Dear Stephen Walther,
Please give clear information about MicrosoftAjax.js status,
Can we assume all *.js that is included on asp.net MVC 2 is supported ?
calling WCF service is easier at microsoft ajax libary than using jQuery
creating Object oriented stuff/model @mvvm pattern also easier at microsoft ajax library
we love stringBuilder, Array extension, asp.net authentication
however,
animation is better at jQuery, some other stuff, dom manipulation, dom transversal
your statement that microsoft ajax client side is shifted to jQuery is too confusing, stuff that i just mention is client side i think
script id="movieTemplate" type="text/html"!!! THIS THING IS NOT STANDARD AND INTRODUCE BUG IN FUTURE, DONT CARE WHATEVER browser did which such tag at this moment
I better use StringBuilder from microsoft ajax library, to build the template/generate html stuff then inject it using jQuery into DOM
dont u see how nice is microsoft jax and jQuery together ???
sorry for a long post