📜 ⬆️ ⬇️

Grails, jQuery, AJAX: do anchor-navigation. Part 2 final

Complete and incomplete pages


We continue to talk about anchor-navigation . Our goal is to make a working application on Grails.

There is one subtlety. I really want the page to be shown in full version (with a header, navigation, etc.), and in the shortened version (for AJAX-calls). However, typing / my-app / do / receipts , we get the full version. Now it looks like this:

Oops! We must somehow distinguish the situation when the page is the main one and when it is internal. To do this, we write a small filter:

grails-app/conf/PartialPageLoadFilters.groovy
  def filters = { partial(controller: "*", action: "*") { before = { //  AJAX-? if (request.xhr) { //     . request.partialPage = true } true } } } 

Note the use of the magic attribute request.xhr provided by Grails. Its presence means that the current request is invoked via AJAX. Most browsers report this to the server through a special HTTP-Header. Above, I simply declared all AJAX requests to be "internal"; in a real application, the situation can be more complicated.
')
Now I can use the request.partialPage flag everywhere. You can make a separate layout for the internal pages, but I preferred to just stupidly make such inserts into the main layout:

grails-app/views/layouts/main.gsp
 %{--   --}% <g:if test="${request.partialPage}"> <g:layoutBody /> </g:if> <g:else> %{--    --}% <html> <head> ... </head> <body> ... <div id="pageContent"> <g:layoutBody /> </div> ... </body> </html> </g:else> 

We have achieved full transparency (for the controller and GSP) in which of the page options to show.

Bookmarks and history


So, we have three screens switched through AJAX:
/ my-app / # do / receipts/ my-app / # do / buy/ my-app / # do / feedback

Everything is very cool, but as it turns out, our “dynamic” links cannot be bookmarked. The fact is that they contain an anchor-tail, which is not transmitted to the server. Therefore, the server when downloading such a URL does not know which of the internal pages to show.

About anchor knows only javascript. This solution suggests itself: first load the base page with JavaScript, then run the code that defines the current anchor and loads the inside using AJAX. Especially without bothering, I wrote this code:

web-app/js/application.js
 $.ready(function() { $('#pageContent').html('...') .load(buildURL(document.location.hash), function() { //   updateNavLinks(); }); }); 

This code only demonstrates the idea. If desired, this code can be finished to a more beautiful state, but the essence will not change: first you have to load the basic wrapper, then the user will have to wait for the internal part to load. For example, Facebook usually does not show anything at all until the inside is loaded - a matter of taste.

And what about the story? When navigating Back / Forward, our $ .ready event will not work. The browser considers such transitions as a “jump” from one anchor to another, i.e. just scrolling through the page. There are no uniquely identified JavaScript events. What to do?

One way to solve this (rather brutal in itself) is to periodically check the document.location.hash property for changes. If suddenly the current anchor has changed, you need to overload the inside of the page.

 function checkLocalState() { if (document.location.hash && document.location.hash != currentState) { currentState = document.location.hash; $('#pageContent').html(' , ...') .load(buildURL(currentState), function() { //   updateNavLinks(); }); } } 

Now we check the change of anchor every 500 milliseconds:

 $.ready(function() { setInterval(checkLocalState, 500); }); 

Now our application will respond to Back / Forward transitions, but with a half second delay. This delay (sometimes annoying to the user) can be seen on many large sites using a similar navigation scheme. If you reduce the spacing, the background javascript will eat more resources. If the interval is increased, the reaction time will increase. In general, you have to pay for everything.

Summary


We created the Grails + jQuery application with AJAX navigation, which:
  1. Reloads only the internal contents of the page without reloading the entire page.
  2. Correctly saves the state of the page in the address bar, i.e. Suitable for bookmarks and transfer links to friends.
  3. Correctly responds to Back / Forward transitions in the browser.
  4. Allows you to develop server code "in the old way", without bothering with the new rules of the game, because All page loading logic is made transparent (for controllers and GSP pages).
  5. Links can be opened in a new window and they will work correctly.
  6. I note that the links in our application are no different from regular links, with the exception of the pound ( # ) at the beginning of the URL! After all, we carefully carried away all the logic of the links in the jQuery-code.

Of course, in a real application, the code given here will have to be improved, in particular, to more accurately take into account situations where there is no anchor, use a more complex link building scheme, etc. However, I hope that he successfully demonstrates the idea and solves most of the problems with anchor-navigation.

References:
  1. http://yensdesign.com/2008/11/creating-ajax-websites-based-on-anchor-navigation/
  2. GWT Tutorial - Managing History and Hyperlinks

Source: https://habr.com/ru/post/108650/


All Articles