Reputation: 874
In the application i am developing, it needs entirely two different views for Desktop and Mobile. Not possible using CSS as content is entirely different.
What I have done?
I had checked whether it is Desktop/Mobile in Routing file
using code const isMobile = window.innerWidth < 768;
And in path component: component: isMobile ? MobileComponent : DesktopComponent
This is working perfectly in development environment. But while production build this fails ng serve --prod
(obviously Angular 5)
Issue:
No errors at all, According to isMobile
true/false it should load MobileComponent/ DesktopComponent. But it does not load even if isMobile is true/false
Always loads MobileComponent in both Desktop & Mobile. while isMobile
value is getting calculated correctly, true
for Mobile
and false
for Desktop
I think the reason is the routes are getting compile already before sending to client.
Workaround tried but not working:
Used a if..else condition, while calculating isMobile
and giving that variable (component) instead of ternary operation in Routing file
Any way:
Is there any way I can use to achieve the same functionality?
Thanks in advance
Upvotes: 18
Views: 16255
Reputation: 2889
Directly make changes in the routes like this -
const routes: Routes = [{
path: '',
component: window.screen.width > 767 ? WelcomeDesktopComponent : WelcomeMobileComponent
}];
Upvotes: 5
Reputation: 1617
I agree with @CarbonDry that using a logic in your RoutingModule is the best way.
However I think using window size is a poor way to detect device type. Of course, it depends on the use case - if you simply need to show different UI for small screens, window.innerWidth
will do. If you want separate functionality for mobiles, it might not be just enough.
There are various ways you could check for device type, for example you can use navigator.orientation === undefined
to check if a device is desktop (because desktops do not support navigator.orientation
.
Lastly, you could always use UserAgent
detection. For that, refer to this thread https://stackoverflow.com/a/13819253/8775880
So in the end, your code might look like this
const isDesktop(): boolean => {
return navigator.orientation === undefined;
}
{
path: 'path',
loadChildren: () => {
if(isDesktop())
return import('./desktop.module').then((m) => m.DesktopModule);
return import('./mobile.module').then((m) => m.MobileModule);
}
}
Edit
Keep in mind, however, that loadChildren
will run only once when the path is loaded for the first time. So again, you might want to consider simply checking the screen dimensions. Let's say that 768px
works for portrait on phone, but what if I open the site in landscape mode? In some situations, even landscape mode requires mobile UI. But if you only check client width, you will get desktop version.
Upvotes: 10
Reputation: 850
Don't use canActivate or route guards, because they need to be used for authentication etc.
New way:
{
path: 'your-path',
loadChildren: () => {
if(window.innerWidth > 768 ) {
return import('./your-desktop.module').then(m => m.YourDesktopModule)
} else {
return import('./your-mobile.module').then(m => m.YourMobileModule)
}
}
}
Upvotes: 10
Reputation: 7733
As I said in the question comment section, route guards would be a good solution for this purpose.
The MobileGuard
would look like this :
export class MobileGuard implements CanActivate {
constructor(private _router: Router, private _mobileService: MobileService) {}
canActivate(): boolean {
const isMobile = this._mobileService.isMobile();
if(!isMobile) {
this._router.navigate(['/desktop']);
}
return isMobile;
}
}
The same for the DesktopGuard
.
The user trying to access any of the routes, would be redirected to the right one.
Here is a running example with this suggested solution.
And here is the stackblitz editable version.
Upvotes: 13