问题
I want to switch between a desktop and mobile template depending on the screen width to ensure my application is responsive. I am trying to do the following:
@Component({
selector: 'app-root',
templateUrl: "./" + (window.innerWidth < 768) ? "app.component.html" : "app.component.mobile.html",
styleUrls: ['./app.component.css']
})
However, this is not working. Instead of the template loading, the string, "app.component.html"
, appears on the screen instead.
What is even more interesting is that, if I use the following:
@Component({
selector: 'app-root',
templateUrl: "./" + (false) ? "app.component.html" : "app.component.mobile.html",
styleUrls: ['./app.component.css']
})
The page still only shows the string "app.component.html"
.
Is there no support for using conditional statements as the value for the templateUrl
field in the @Component
decorator?
If not, what is an alternative solution I could use to achieve this level of responsiveness that is still modular and follows best practices?
Update: I got this to work by using ng serve --aot
instead of just ng serve
. However, I decided to not go through with this idea because it does not switch templates as the window resizes.
回答1:
your approach here is off. Templates are assigned to components at build time, not runtime and Angular will build all of it's components, well before any window exists with a width to write a conditional off of. You need to set up logic to tell your app when to show which component.
The "best practice" (IMO) here, if you can't do responsive design (note: it's important to understand your audience and how the app will be used. I always try to opt for a mobile first responsive design, but also recognize this isn't always appropriate), is to have 2 components, and use route guards to enforce the correct component.
@Injectable()
export class MobileGuard implements CanActivate {
constructor(
private router: Router
) { }
canActivate() {
if (window.innerWidth >= 768) {
this.router.navigate(['/']);
return false;
}
return true;
}
}
@Injectable()
export class DesktopGuard implements CanActivate {
constructor(
private router: Router
) { }
canActivate() {
if (window.innerWidth < 768) {
this.router.navigate(['/m/']);
return false;
}
return true;
}
}
then define your routing structure somewhat like this:
const routes: Routes = [
{
path: '',
component: AppComponent,
canActivate: [DesktopGuard],
children: [... desktop routes ...]
},
{
path: 'm',
component: MobileAppComponent,
canActivate: [MobileGuard],
children: [... mobile routes ...]
}
]
as for the components themselves, your mobile component just extends your non mobile component and has a different template / styles associated.
an alternative approach here is to do something like this:
export class WrapperAppComponent {
isMobile: boolean;
constructor() {
this.isMobile = window.innerWidth < 768;
}
}
with template like:
<desktop-app *ngIf="!isMobile"></desktop-app>
<mobile-app *ngIf="isMobile>></mobile-app>
but this isn't a very scalable approach and has the same "duplication" of components.
回答2:
I believe you can you do this -
export function getTemplateUrl() {
if (window.innerWidth < 768)
return "app.component.html";
else
return "app.component.mobile.html";
}
@Component({
selector: 'app-root',
templateUrl: getTemplateUrl(),
styleUrls:['./app.component.css']
})
and then compile your application using aot - ng serve --aot . this works with lower version of angular, I haven't tried with Angular 7 but should work.
来源:https://stackoverflow.com/questions/57172724/switch-between-mobile-or-desktop-template-using-condition-in-templateurl-angula