Tuesday 11 July 2017

Implementing routing in a SPA using AngularUI Router

Introduction

In this blog, we’ll give you a rundown of how we’ve implemented routing in our single page project management tool – PineStem.
Routing is a process of navigating the user to the desired location based on the action they perform.
Maintaining the user’s navigation history is a major challenge while developing a single page application(SPA).
To overcome this problem, we implemented a simple stack based solution which only involves pushing and popping an object with required properties.

Demo

You can find the sample code and a demonstration in the Plunker here – https://plnkr.co/OnBe1bc9Q7h1tYBK1pSY?p=info

Implementation

For PineStem, we’ve used a popular routing plugin named AngularUI Router.The idea behind our implementation is quite simple. We store the parameters that are required to navigate back to a particular state in an object and push it into an array.
AngularUI Router provides us an event called $stateChangeSuccess, which gets triggered on every successful state change. We store the information that is needed to navigate to that particular state on this event, which includes the stateParams, URL, a template that has to be loaded and name of the state. Whenever a user tries to go back by clicking on exit/cancel button or browser’s back button, we pop out the latest element in the array and use that for the state change. This way, we can maintain a stack to hold the user navigation history accurately.
A typical object that we store on each state change could be the one that is shown below –
Routing object
In PineStem, we have two ways of navigation. One is through the main window and another way is through the sidebar that is present on the left side.
Screenshot of the application is shown below.
PineStem
In order to identify the mode of user’s navigation, we used two flags –
  1. isFromNavBar  – It is set to true if the user navigates through the sidebar.
  2. isCancelOrSave   It is set to true if the user navigates back through cancel/exit button in the main window.
Using the above-mentioned flags, we track user’s way of navigation and perform the necessary action.
  • When a user traverses through the main window, we maintain their navigation history by pushing the state information into the array.
  • If the user tries to navigate through the sidebar (isFromNavBar is true) then we clear the route history.
  • If the user clicks on the exit/cancel (isCancelOrSave is true) button of any entity, then we pop out the last element in the routeHistory and redirect user to the previously visited state. To know more about isCancelOrSave flag, please visit Handling back or exit button.

Logic breakdown

Let us see the actual logic in detail –
Following are the steps that take place when a user tries to navigate around three modules namely module_one, module_two, and module_three.
Step 1 – Assume an empty array. Eg: $routeHistory = [ ];
Step 2 – Now when the user tries to open module_one, there is no need to perform any action as this is their first step.
Step 3 – From module_one user opens module_two. Then we push an object (with details as discussed above) into the array. Thus, $routeHistory = [module_one_route]
Step 4 – Then, from module_two user tries to go to the module_three. Now, we will push the object related to module_two into the array. So, our array becomes
$routeHistory = [module_one_route, module_two_route]
Step 5 – Let’s say the user clicks on exit/browser’s back button in the module_three. Then we need to check the $routeHistory variable and if it is not empty, the latest entry is popped out. We use this object to render the last state.

Handling the back or exit button

We can find exit/cancel button in various sections of the application. On clicking this button, the user gets redirected to the previously visited state. As expected $stateChangeSuccess event triggers, and we save the last state visited by the user. Navigation by browser’s back button also triggers $stateChangeSuccess event.
Saving the state on the back/exit leads to a continuous loop.
Consider an example – Assume there are three pages named A, B, and C.
  1. User visits a page named page A. From page A, user visits page B, then from page B to page C. By now, the stack is filled with [pageA, pageB].
  2. Then, he/she tries to go back by clicking on the browser’s back button. As expected, they are redirected to page B using the latest entry of the stack.
  3. Along with the redirection, page C is saved on successful state change which makes the contents of the stack – [pageA, pageC].
  4. Then, if the user tries to click on the back button again expecting to be in page A, instead they will get redirected to page C. This happens because page C is the latest element in the stack.
The same is illustrated in the image below.
   Back button Loop Execution
In order to skip the saving of the last state, we set the flag isCancelOrSave to true. Whenever a user clicks on the exit/cancel button or the browser’s back button, isCancelOrSave state is set to true.
Then on the $stateChangeSuccess event, the following code snippet is executed.
Setting the isCancelOrSave manually when the user presses the back or exit button is simple enough, but doing so on the browser’s back button click needs another small snippet of code to be added in the $stateChangeSuccessevent.

Browser compatibility

The window.event property is available in Google Chrome and Edge only. So, the above-mentioned solution is applicable only for Chrome and Edge.

Different scenarios

Let us see a few scenarios that we handled using the above implementation.
Case 1
  1. User starts their navigation from the projects list module.
  2. Then opens a project.
  3. Next, to a task in the project.
  4. And then to the open bugs in that particular task.
  5. Finally, he/she goes to a bug.
  6. Reverses all the above steps by clicking on the exit/cancel button or browser’s back button to reach projects list again.
Above mentioned steps are illustrated through an image
Navigation via Back button
Case 2
  1. User starts their navigation from projects list.
  2. Then opens a project.
  3. From there he/she clicks on some task.
  4. Then, to the open bugs present on that task.
  5. They then click on the ‘Create new task’ link present in the sidebar.
  6. In the new task module, they press the exit button. Then, they will be redirected to the dashboard.
Navigation via Exit

No comments:

Post a Comment

Voice of the Customer (VOC) – Dynamics 365 CRM

Tags:   Dynamics 365   Dynamics CRM   feedback   survey   VOC   Voice of customer Introduction To Voice of the Customer For any bus...