Implementing the View Stack
Implementing the View Stack
===
Implementing the View Stack
If you haven’t noticed already, it’s pretty frustrating that, when we hit a particular screen in our application, the only way to get back to the previous screen is to refresh the page. This isn’t going to cut it, so it’s time to do something about it.
The first thing that is required will be to implement some kind of view or screen stack. We need a mechanism that will allow us to keep track of which screens have preceded this one. The best place to implement this functionality will be in the switchView private function in the PROWEBAPPS.ViewManager module. Let’s modify that function now:
function switchView(oldView, newView) { var ii, menu = jQuery("#menu").get(0);
// if the old view is assigned, then push it onto the stack updateViewStack(oldView, newView);
... } // switchView
As you can see, we have added a call to a new function called updateViewStack passing through the old and the new view. The implementation of updateViewStack is quite simple, and is used to determine whether our movement from the oldView to the newView should change the state of the stack.
function updateViewStack(oldView, newView) { // first let's determine if we should push onto the stack
var shouldPush = oldView && ( (viewStack.length === 0) || (newView && (viewStack[viewStack.length - 1].id != newView.id))
// if we should push onto the stack, then do so, otherwise pop if (shouldPush) {
viewStack.push(oldView);
// if the back action does not exist yet, then create it if (! backAction) {
backAction = new module.ViewAction({ label: "Back", run: function() {
92 CHAPTER 4: Constructing a Multipage App
subModule.activate(viewStack[viewStack.length - 1].id); } }); } // if } else if (oldView && newView && (viewStack.length > 0)) {
viewStack.pop(); } // if..else } // updateViewStack
In the preceding code, the shouldPush variable is initialized based on the presence of having being passed an oldView, and the view stack being either empty or having the last item in the stack being something other than the newView we are transitioning to. If we are transitioning back to the view that is the most recent view that was pushed to the stack, then it will be popped off as a result.
With the view stack in place, the back action can be used to take the user back to screens that they were on previously without needing to be told in each and every case what that screen was. This in turn is going to save a lot of effort coding in the long term.
NOTE: The backAction ViewAction is initialized in the preceding function as opposed to variable definitions of the module (which you can see towards the top of the module definition). This is not because I am a massive lazy-loading fan (not creating variables until they are needed), but, rather, it is because of the way I have implemented the module pattern.
In JavaScript, a variable cannot be referenced until the definition of that variable is complete— which is fair enough. If we try to reference the ViewAction class of the PROWEBAPPS module (using module.ViewAction), it fails. If we create it later, once the definition is complete, everything’s fine.
If you encounter this situation, it may be worth considering refactoring your code to define modules/classes that are required in a module definition as a separate, private module/class and then including it in the exported module by using a simple assignment.
To make use of our newly created stack, we are going to need to modify the getViewActions and getAction private functions in the ViewManager module. Here is a section of the ViewManager module that highlights the required changes:
ViewManager: (function() { var views = {}, activeView = null,
viewStack = [], backAction = null;
function getViewActions(view) { var html = ""; for (var ii = 0; view && (ii < view.actions.length); ii++) {
html += "<li>" + view.actions[ii].getAnchor() + "</li>"; } // for
CHAPTER 4: Constructing a Multipage App
// if the view stack is active, then add a back action if (viewStack.length > 0) {
html += "<li>" + backAction.getAnchor() + "</li>"; } // if
return html; } // getViewActions
function getAction(view, actionId) { // extract the id portion from the action id actionId = actionId.replace(/^action_(\d+)$/i, "$1");
if (backAction && (backAction.id == actionId)) { return backAction; } // if
// find the specified view in the active view and execute it for (var ii = 0; ii < view.actions.length; ii++) {
if (view.actions[ii].id == actionId) { return view.actions[ii]; } // if } // for
return null; } // getAction
You can see that two additional variables have been added for the viewStack and the backAction. Additionally, the getViewActions and getAction functions are modified to properly handle the back action behavior. In the case of getViewActions, the function checks whether the viewStack contains any items, and, if it does, includes the backAction in the actions that will be displayed for the current view. The changes to the
getAction method provide the function with a mechanism for providing the backAction handler even though it hasn’t been explicitly defined.
One final piece of the puzzle remains. We require a method in the PROWEBAPPS.ViewManager module that will allow us to initiate going back manually:
ViewManager: (function() { ...
var subModule = { ...
back: function() { if (backAction) { backAction.execute(); } // if },
return subModule; })()
94 CHAPTER 4: Constructing a Multipage App
This method will be called in instances where you have completed a screen and need to return the user to the previous screen. For instance, we need to change the function call PROWEBAPPS.ViewManager.activate("main") to PROWEBAPPS.ViewManager.back() in our submit handler for the task entry form to make sure the application flows correctly.
And with that, we are done. More can be done to the application itself to polish it up, but there are good bones to work with here. There are a number of possible extensions that could be made to the application to enhance it from this point, so please feel free to try anything that interests you.
Summary
In this chapter, we explored one way of implementing a view manager useful for building
a multipage web app that operates correctly on an Android device. This included looking at different ways of navigating through an application and implementing some intelligence to create appropriate navigation controls.
We also finished having a look at the Web SQL Database API by implementing the code required to retrieve items from our database and display them in the app.
By now, you should be relatively comfortable with the JavaScript module pattern, and
be able to implement it in your own applications if you choose to. In the next chapter, we will go through how we can synchronize the data in our To Do
List with an online data store. This will enable us to create other clients (such as a desktop web application) that can view the data we are collecting in our mobile app.
Chapter