How can I dynamically reference two template HTML files (one for mobile and one for desktop) within a single component in Angular 6?

Here is the approach I have taken.

Organizational structure

mobile-view.component.html

<p> This content is for mobile view </p>

desktop-view.component.html

<p> This content is for desktop view </p>

mobile.component.ts

import { BaseComponent } from './base.component';

@Component({
    selector: 'app-mobile-view',
    templateUrl: './mobile-view.component.html'
})

export class MobileComponent extends BaseComponent { }

desktop.component.ts

import { BaseComponent } from './base.component';

@Component({
    selector: 'app-desktop-view',
    templateUrl: './desktop-view.component.html'
})

export class DesktopComponent extends BaseComponent { }

base.component.ts

@Component({
   selector: 'app-root',
   template: `<app-mobile-view *ngIf="isMobileView"></app-mobile-view>

    <app-desktop-view *ngIf="!isMobileView"></app-desktop-view>`
})
export class BaseComponent implements {

   isMobileView: boolean;

   constructor(){
        if (navigator.userAgent &&
           (navigator.userAgent.match(/Android/i) ||
           navigator.userAgent.match(/webOS/i) ||
           navigator.userAgent.match(/iPhone/i) ||
           navigator.userAgent.match(/BlackBerry/i) ||
           navigator.userAgent.match(/Windows Phone/i))) {

           this.isMobileView = true;
        } else {
           this.isMobileView = false;
        }
   }

   ngOnInit() {
    // code
   }

   // various methods
}

In this method, all main logic and binding variables are kept in base.component.ts file

Mobile component and Desktop component extend Base component to access all methods and variables

Note:- This code example is just a demonstration of what I have attempted.

Requirement :

  1. An AOT build is required.
  2. If there is a better approach or standard practice for achieving this?

  3. If there is a way to set the template dynamically based on the device that made the request. Refer to the code in base.component.html constructor for code to fetch userAgent information (provides info about the device making the request), which I am currently using.

Previous method used:-

main.component.html

@Component({
   selector: 'app-root',
   template: function () {
     if (isMobileUser()) {
            return require('./mobile-view.component.html');
       } else {
            return require('./desktop-view.component.html');
       }
     }(),
    styleUrls: ['./main.component.scss']
})

export class MainComponent {
}
  1. This approach resulted in an AOT build failure
  2. and the use of function call in the component decorator is deprecated

Answer №1

Here is a simpler approach compared to the one mentioned above. By using ngContainer with ngTemplateOutlet, you can dynamically inject templates into containers based on conditions.

@Component({
    selector: 'app-mobiledesktop-view',
    templateUrl: './mobiledesktop-view.component.html'
})

export class MobileDesktopComponent { }


**Template:**

<ng-template #mobileView>
  This is mobile view
</ng-template>

<ng-template #desktopView>
  This is desktop view
</ng-template>

<ng-container *ngTemplateOutlet="isDesktop ? desktopView : mobileView">

</ng-container>

Using Dynamic Component:

@Component({
    selector: 'app-desktop-view',
    template: 'This is desktop view'
})

export class AppDesktopComponent { }

@Component({
    selector: 'app-mobile-view',
    template: 'This is mobile view'
})

export class AppMobileComponent { }

@Component({
    selector: 'app-container-view',
    template: ' <ng-container #messagecontainer></ng-container>'
})

export class AppContainerComponent { 
     private componentRef;
     @ViewChild('messagecontainer', { read: ViewContainerRef }) entry: ViewContainerRef;
     constructor(private resolver: ComponentFactoryResolver) { }

     ngAfterViewInit(){
        const component = (isDesktop) ? AppDesktopComponent : AppMobileComponent;
        const factory = this.resolver.resolveComponentFactory(component);
        this.componentRef = this.entry.createComponent(factory);
        //this.componentRef.instance.data = appData;
     }

     ngOnDestroy() {
        this.componentRef.destroy();
     }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Unit testing for Angular service involving a mock Http GET request is essential for ensuring the

I am seeking guidance on how to test my service function that involves http get and post calls. I attempted to configure the spec file by creating an instance of the service, and also consulted several sources on creating a mockhttp service. However, I enc ...

Resolve the conflict with the upstream dependency when setting up a fresh Angular project

Software Info: Angular CLI: 12.1.1 Node: 14.17.3 Package Manager: npm 7.19.1 An error occurred while attempting to create a new Angular project. npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree npm ERR! npm ERR! While re ...

Angular version 9.1 includes a myriad of functioning routes, with the exception of just one

UPDATE: The issue was not related to the API, but rather with Angular. Please refer to the answer provided below for more details. I have been using this particular App for years without any route-related problems until recently. After deploying some upda ...

Configuring ESLint, Prettier, and TypeScript in React Native: A Step-by-Step Guide

Could you provide guidance on setting up ESLint, Prettier, and TypeScript in React Native? I'm currently using absolute paths to specify components. Can you confirm if this setup is correct? tsconfig { "extends": "@tsconfig/react-n ...

Angular: determining if the current route or page is secured by a guard

I am currently working with Angular 9 and I was wondering if there is a way to determine if the current page is protected or guarded during the APP_INITIALIZER phase. Within my APP_INITIALIZER setup, I need to be able to identify whether the route being a ...

typescript set parameter conditionally within a function

For my upcoming app, I am working on an API that will utilize Firebase FCM Admin to send messages. Below is the code snippet: import type { NextApiRequest, NextApiResponse } from "next"; import { getMessaging } from "firebase-admin/messaging ...

Creating a new Angular2 component for a separate URL path

In my scenario, I have a PageComponent that gets refreshed with new data when the URL changes (using PageService). It currently utilizes the same PageComponent object, but I am looking to make it a new object when the URL changes. 1st Question: How can ...

Exploring ways to destructure the useContext hook with a null default value in your Typescript code

Initially, I set up a context with a null value and now I am trying to access it in another component. However, when I destructure it to retrieve the variables from the context, I encounter a TypeScript error: Property 'users' does not exist on ...

Access Denied: Origin not allowed

Server Error: Access to XMLHttpRequest at '' from origin 'http://localhost:4200' has been blocked by CORS policy. The 'Access-Control-Allow-Origin' header is missing on the requested resource. import { Injectable } from &apo ...

Struggling to access the properties of a Material-UI Button

import * as React from "react"; import { styled } from "@mui/material/styles"; import MuiButton from "@mui/material/Button"; import Slider from "@mui/material/Slider"; interface Props { type: "primary" | ...

Is there a way to trigger a request to the backend when the user closes or refreshes the browser?

My Objective: I am working on a lobby feature that updates automatically when a player leaves. Using backend requests and sockets, the lobby is updated to display the current list of players after someone exits. The Challenge: I am faced with the issue ...

Restricting enum type to only one member

enum Value { First, Second, } interface Data { value: Value number: number } interface SubData { value: Value.Second } function calculation(input: SubData){ return; } function initiate(){ const input : Data = { numbe ...

Unpacking and reassigning variables in Vue.js 3 using TypeScript

I am working with a component that has input parameters, and I am experimenting with using destructuring assignment on the properties object to reassign variables with different names: <script setup lang="ts"> const { modelValue: isSelected ...

Edit CSS attributes within Angular 2+ framework

When using jQuery, we have the ability to do the following: JQuery('.someStyle') .css({"background", "red"}) This allows us to directly change the CSS property in style. While working with Angular 2+, we can use [style.<property>] for ...

Is it possible to set a form control value as an object and display its label within an input field?

I am working on a basic form that includes an input field with autocomplete using Angular Material components. The issue I am facing is that when I select a value from the autocomplete box, the input field displays [Object object] as the value instead of t ...

Troubles arise with a Web API ASP .NET / Angular2 Session hosted on Azure

Hello, this is my first question here so please let me know if something doesn't fit. Currently, we are working on developing a Web API using C# and Angular2. One of the features requires the session to be efficient, but despite going through numerou ...

Retrieving decimal value from a given string

Currently, I am working with Google Maps and encountering an issue with distance values being returned as strings like 1,230.6 km. My goal is to extract the floating number 1230.6 from this string. Below is my attempted solution: var t = '1,234.04 km ...

The automatic inference of function argument types and the implementation of conditional types

I'm facing a specific scenario: There's a function that takes in a boolean and returns either a RealItem or an ImaginaryItem. I'm using conditional types to determine the return type based on the boolean argument. type RealItem = { color: s ...

Exploring nullish coalescing with undefined values

My function is set up to make API calls: interface getEventsPropsShape { eventId?: string; accountId?: string; eventsStartAfter?: string; } const getEvents = async ({ eventId, accountId, eventsStartAfter, }: getEventsPropsSha ...

Tips for efficiently resolving and compiling a bug within an NPM package, ensuring it is accessible to the build server

This question may seem a bit unconventional. I am currently using an npm package that includes built-in type definitions for TypeScript. However, I have discovered a bug in these definitions that I am able to easily fix. My goal is to make this updated ve ...