Going Desktop to Mobile view by configuring the Angular router
Tags: angular, architecture, responsive, webdev
Published: 2019-07-09 03:22:01

Working on an emergency application (with live data) using .net and angular.  The backend is .net with SQL server and SignalR on Azure.  This application is sales driven product, we came out first with desktop version and then mobile friendly version due to way the market and 90-80% of users are on desktop view.

This article describes how we architect our application do be responsive.  Basically, going from an already existing desktop web application to responsive application.  When referring to word “mobile” in article, it is not a mobile native application or Progressive Web App, it is referring to responsive application on different tables and mobile devices.

#Architecture and Setup#
We started by in our angular application under root folder “src”.  We created a folder called “mobile”.  We have the “app” folder for main desktop view, it can be renamed to “desktop”.  This gave us a whole new place to have our mobile code and not been in the same folders with all other code, it is more organized, clean and separated from all other code.

In app router module “AppRoutingModule”, when application get loaded.  We load an array of all paths of the application, from “app” and “mobile” folders.  When application knows the size of window “window.innerWidth” it will modify the path array and rests the route configuration by calling "this.route.resetConfig()".  Here we also listen to “window:resize” in the main component of the application for window resizing, and the router path gets modified and then router configuration gets reloaded.  So, user can go from desktop to mobile view and vice and versa.

```javascript
const desktopPreloadModules = [
  {
    path: 'dashboard', loadChildren: () =>
      import('app/modules/dashboard/dashboard.module')
        .then(mod => mod.DashboardModule)
  },
  {
    path: 'debug', loadChildren: () =>
      import('app/modules/debug/debug.module')
        .then(mod => mod.DebugModule)
  }
];

const mobilePreloadModules = [
  {
    path: 'dashboard', loadChildren: () =>
      import('mobile/modules/dashboard/dashboard.mobile.module')
        .then(mod => mod.DashboardMobileModule)
  },
  {
    path: 'debug', loadChildren: () =>
      import('mobile/modules/debug/debug.mobile.module')
        .then(mod => mod.DebugMobileModule)
  }
];

const appRoutes: Routes = [
  { path: 'login', component: LoginComponent },
  {
    path: 'main',
    component: MainComponent,
    canActivate: [AuthGuard],
    resolve: [AppDataResolver],
    children: [...desktopPreloadModules, ...mobilePreloadModules]
  },
  { path: '', redirectTo: '/main', pathMatch: 'full' },
  { path: '**', component: LoginComponent }
];

@NgModule({
  imports: [RouterModule.forRoot(appRoutes, { preloadingStrategy: SelectiveStrategy, enableTracing: false, scrollPositionRestoration: 'enabled' })],
  providers: [SelectiveStrategy],
  exports: [RouterModule]
})
export class AppRoutingModule {
  constructor(…) { … }
}
```

There is also CSS files that styling changes depending on the window size, we used media query for that, by calling: ```@media only screen and (max-width: ####px)```

In our application we also have some dynamic dialog boxes, we also override those components by reloading them either mobile view or desktop view.

After route is change the all components (that is in the current view) needs to be reloaded.  Here, we solve this by simply navigating to and empty path this basically reloads all current component in the DOM (it is not refresh from server.)

#Mobile Implementation#
In the mobile for with similar path tree as desktop “app” folder, by using OOP inheritance, polymorphism and overriding methods.  We could access all of the functionalities from desktop services and components and reused the code, by extending from same components.  Following the open/closed principle.  For example:

```javascript
@Component({
  selector: 'my-mobile-component',
  templateUrl: './my.mobile.component.html'
})
export class MyMobileComponent extends MyDesktopComponent { }
```

In case mobile functionality is different than desktop, we override the desktop method in the mobile folder.

In our application which is medium to advanced application complexity.  There is only one place that it is checking if application is mobile or desktop and that is in the “AppRoutingModule” there no “if (mobile) do this else do that” outside the router.  We follow and stick with this pattern due to the fact that the application could be very messy.  If we have a mobile specific component or function with extending the class from desktop and override or add mobile specific functions or view.  Following the single responsibility principle.

#Pros#
* Clean and organized code.
* Easy to implement the mobile view application.
* Reuse of the code, this saves us lots of time to impalement and test.  The desktop code is already in production and been used by users, we know if works.  So, we are confident that code works.
* Follows the single responsibility principle
* Follows the open/closed principle

#Cons#
* If we want to override a desktop behavior or functionality we will need to extend it in mobile.  This can give a little complexity to some deeper functionalities.  However, doable by refactoring and using SOLID principles.
* Can easily get a messy code if we breaking the pattern if someone writes “if (mobile) do this else do that” way or some other way.