Switch between mobile or desktop template using condition in templateUrl (Angular 7)

房东的猫 提交于 2020-01-16 19:07:13

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!