First we will update our dynamic data controller method to return a set of books.
@RequestMapping(value="/dynamicData", method=RequestMethod.GET) public @ResponseBody ListNow that out ajax call will return the list we have two options for displaying this data to the user. The first would be programmatically generating html from the json content. The second would be to use a javascript templeting plugin. By utilizing a templeting plugin we will have more concise code that is easier to maintain. This demo will use the recently added top level jQuery template plugin, currently in beta.getDynamicData(Model model){ List books = new ArrayList (); Book book = new Book(); book.setId(1l); book.setTitle("The Road to Serfdom"); book.setAuthor("Friedrich Hayek"); books.add(book); book = new Book(); book.setId(2l); book.setTitle("Capitalism and Freedom"); book.setAuthor("Milton Friedman"); books.add(book); book = new Book(); book.setId(3l); book.setTitle("The General Theory"); book.setAuthor("John Keynes"); books.add(book); return books; } private class Book { private Long id; private String title; private String author; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } }
With the goal of displaying the books in a standard jqm styled list the following simple template was created. It will style title and author and add the books id as a data element that will be helpful for onclick methods.
<script id="bookTemplate" type="text/x-jquery-tmpl"> <li data-id=${id} class='bookButton'> <h3>${title}</h3> <p>${author}</p> </li> </script>As this template will be used repetitively we will precompile it to a named template. This should speed up execution time. See http://boedesign.com/misc/presentation-jquery-tmpl/#13.
$('#bookTemplate').template('bookTemplate');Next we will update bar with the shell of a jqm list to hold the data.
<div id="bar" data-role="page"> <div data-role="header"> <h1>Bar</h1> </div> <div data-role="content"> <ul data-role="listview" id="dynamicContentHolder"> </ul> <br/> <a href="#foo" data-inline="true" data-role="button" >To foo</a> <a id="buttonSignOut" name="buttonSignOut" href="#" data-role="button" data-inline="true">Sign Out</a> </div> </div>Finally we will update the ajax call to parse the json response content, generate html content with the template, and insert the content into bar’s jqm list. Finally we will refresh the listview to allow jqm to apply appropriate styling to the content.
$('#bar').live('pagebeforeshow',function(event, ui){ $.mobile.pageLoading(); $('#dynamicContentHolder').text(''); var dynamicDataResp = $.ajax({ url: "/dynamicData.json", dataType: 'json', async: false, cache: false }); if(dynamicDataResp.status == 200){ var dynamicDataObj = jQuery.parseJSON(dynamicDataResp.responseText); $.tmpl('bookTemplate', dynamicDataObj).appendTo('#dynamicContentHolder'); $('#dynamicContentHolder').listview('refresh'); } ...The next thing I wanted to be able to do, is control navigation and pass information on the selected book when a user selects one off the list. So let’s add a new page for this content.
<div id="bookDetails" data-role="page"> <div data-role="header"> <h1>book details</h1> </div> <div data-role="content"> <span id="bookContent"/> </div> </div>Now as we included the class bookButton on each of our book list items we can register a click handler that will query the id from the element, save it as context information to the page, and navigate to the details page.
$('.bookButton').live('click', function() { var bookId = $(this).jqmData('id'); $('#bookDetails').jqmData('bookId', bookId); $.mobile.changePage('#bookDetails'); });Finally on bookDetail's pagebeforeshow event we can alter the page databased on the bookId metadata stored to the page. The example below simply prints out the info, but using the skills you have learned so far you could easily issue a query here to retrieve additional information on the book.
$('#bookDetails').live('pagebeforeshow', function(event, ui){ var bookId = $('#bookDetails').jqmData('bookId'); if(bookId != null){ $('#bookContent').text("Details about book #" + bookId + " here."); } else{ $.mobile.changePage('#error', 'none', false, false); } });As usual here is the complete jqm app.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, minimum-scale=1, maximum-scale=1"> <title>App Name</title> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0a4.1/jquery.mobile-1.0a4.1.min.css" /> <script type="text/javascript" src="http://code.jquery.com/jquery-1.5.2.min.js"></script> <script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery.templates/beta1/jquery.tmpl.min.js"></script> <script id="bookTemplate" type="text/x-jquery-tmpl"> <li data-id=${id} class='bookButton'> <h3>${title}</h3> <p>${author}</p> </li> </script> <script type="text/javascript"> $('#bookTemplate').template('bookTemplate'); $(document).bind("mobileinit", function(){ $('.bookButton').live('click', function() { var bookId = $(this).jqmData('id'); $('#bookDetails').jqmData('bookId', bookId); $.mobile.changePage('#bookDetails'); }); $('#bookDetails').live('pagebeforeshow', function(event, ui){ var bookId = $('#bookDetails').jqmData('bookId'); if(bookId != null){ $('#bookContent').text("Details about book #" + bookId + " here."); } else{ $.mobile.changePage('#error', 'none', false, false); } }); $('#buttonSignOut').live("click", function() { $.mobile.pageLoading(); $.ajax({ url: '/signout', complete: function(transport) { if(transport.status == 200) { $.mobile.changePage('#foo'); } else { $.mobile.changePage('#error', 'none', false, false); } } }); return false; }); $('#signInForm').live("submit", function() { $.mobile.pageLoading(); // Submit the form $.ajax({ type: 'POST', url: '/signin/authenticate', data: $('#signInForm').serialize(), complete: function(transport) { if(transport.status == 200) { history.back(); } else { $('#loginError').show(); $.mobile.pageLoading(true); } } }); return false; }); $('#login').live('pagebeforeshow', function(event, ui){ $('#loginError').hide(); }); $('#bar').live('pagebeforeshow',function(event, ui){ $.mobile.pageLoading(); $('#dynamicContentHolder').text(''); var dynamicDataResp = $.ajax({ url: "/dynamicData.json", dataType: 'json', async: false, cache: false }); if(dynamicDataResp.status == 200){ var dynamicDataObj = jQuery.parseJSON(dynamicDataResp.responseText); $.tmpl('bookTemplate', dynamicDataObj).appendTo('#dynamicContentHolder'); $('#dynamicContentHolder').listview('refresh'); } else if(dynamicDataResp.status == 401){ $.mobile.changePage('#login'); return false; } else{ $.mobile.changePage('#error', 'none', false, false); } }); }); </script> <script type="text/javascript" src="http://code.jquery.com/mobile/1.0a4.1/jquery.mobile-1.0a4.1.min.js"></script> </head> <body> <div id="foo" data-role="page"> <div data-role="header"> <h1>Foo</h1> </div> <div data-role="content"> <h2>Foo</h2> <a href="#bar">To bar</a> </div> </div> <div id="bar" data-role="page"> <div data-role="header"> <h1>Bar</h1> </div> <div data-role="content"> <ul data-role="listview" id="dynamicContentHolder"> </ul> <br/> <a href="#foo" data-inline="true" data-role="button" >To foo</a> <a id="buttonSignOut" name="buttonSignOut" href="#" data-role="button" data-inline="true">Sign Out</a> </div> </div> <div id="bookDetails" data-role="page"> <div data-role="header"> <h1>book details</h1> </div> <div data-role="content"> <span id="bookContent"/> </div> </div> <div id="login" data-role="page"> <div data-role="header"> <h1>Login</h1> </div> <div data-role="content"> <span id="loginError" class="error">Your credentials are invalid. Please try again.</span> <form id="signInForm" data-ajax="false"> <div data-role="fieldcontain"> <label for="login">Username or Email</label> <input id="login" name="j_username" type="text" size="25" autocorrect="off" autocapitalize="off" /> </div> <div data-role="fieldcontain"> <label for="password">Password</label> <input id="password" name="j_password" type="password" size="25" /> </div> <div id="submitDiv" data-role="fieldcontain"> <input type="submit" value="login" data-inline="true"/> </div> </form> </div> </div> <div id="error" data-role="page"> <div data-role="header"> <h1>Error</h1> </div> <div data-role="content"> Click back to return to the previous page. </div> </div> </body> </html>
1 comment:
Thank you for the informative port.
It helped me understand the concept.
Amnon
Post a Comment