Display customizable template according to variable

The answer provided for the issue regarding dynamic template generation based on value instead of variable in this thread was really helpful. However, I'm facing challenges in getting it to work. Here's a simplified example:

export class A {
}

export class MyComponent implements OnInit {

  public controls$ = Observable<any[]>([]);

  ngOnInit() {
    this.controls$.next([new A()]);
  }

  public getControlType(control: any) {
    if (control instanceof A) {
      return "AControl";
    }
    return "";
  }
}

Template:

<div *ngFor="let control of control$ | async">
  {{ getControlType(control) }}
</div>

This yields:

AControl

Everything works as expected up to this point. But when I add a template, an exception is thrown:

<div *ngFor="let control of control$ | async">
  {{ getControlType(control) }}
  <ng-container 
    [ngTemplateOutlet]="getControlType(control)"
    [ngTemplateOutletContext]="{ control: control }">
  </ng-container>
</div>

<ng-template 
  #AControl 
  let-item="control">A Control</ng-template>

This throws:

templateRef.createEmbeddedView is not a function

I am unsure about what modifications are needed for the #AControl template to render within the container.

Answer №1

It appears that the issue lies with

[ngTemplateOutlet]="getControlType(control)"
. While the code for getControlType() is not visible, it seems like it might be returning a string instead of a TemplateRef object. Executing functions in templates is generally discouraged unless using ChangeDetectionStrategy.OnPush, so I recommend implementing a switch statement within your template. However, utilizing

@ViewChild("AControl", {static: true})
AControl: TemplateRef<any>;

will allow you to retrieve the template in your .ts file and return it from the getControlType function.

Answer №2

After reading through D Pro's Answer, I realized that using a ngTemplateOutlet was unnecessary for my specific case, as it seemed overly complex for the simplicity of my needs.

This is how I ultimately solved the issue:

typescript

export class A {
}

export class B {
}


export class MyComponent 
  implements OnInit {

  public controlsTypes$ = Observable<any[]>([]);

  ngOnInit() {
    var value1 = new A();
    var value2 = new B();
    this.controls$.next([
      { control: value1, type: getTypeName(value1)},
      { control: value2, type: getTypeName(value2)},
    ]);
  }

  public getTypeName(control: any) {
    if (control instanceof A) {
      return "AControl";
    } else if (control instanceof B) {
      return "BControl";
    }
    return "";
  }

  public onClick(control: any) {
  }
}

html:

<div *ngFor="let controlType of controlType$ | async"
     [ngSwitch]="controlType.type">
  <ng-template ngSwitchCase="AControl">
    <div (click)="onClick(controlType.control)">{{ controlType.type }}</div>
  </ng-template>
  <ng-template ngSwitchCase="BControl">
    <div (click)="onClick(controlType.control)">{{ controlType.type }}</div>
  </ng-template>
</div>

This code displays both an AControl and BControl, and when either is clicked, the corresponding class instance is passed to onClick().

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

How to set focus on an input element in Angular 2/5

After clicking, the input element is displayed (it is initially hidden). I want this input to be in focus when it appears. This functionality works well when the input is not hidden by *ngIf (#inputElement2). Is there a way to achieve the same for #inputE ...

Enhanced HTML support for * syntax in IntelliJ Angular 2

It appears that IntelliJ 2017.1 does not fully support the * syntax for HTML files with Angular 2. The autocompletion only suggests the template syntax without the star. https://i.stack.imgur.com/k6SuD.png https://i.stack.imgur.com/QfNPH.png Moreover, w ...

The NgModel within the parent component is expected to mirror the state of the child component

My Angular 10 project includes a library with a wrapper component around a primeng-component. The primeng-component utilizes ngModel. I am trying to set the ngModel in the parent-component accessing the wrapper-component, and I want any changes made to the ...

What is the best way to sort through an array depending on a specific sequence of elements provided

I am trying to create a custom pipe in Angular 5 that filters an array of events based on a given sequence. For instance, if my data is: ["submit", "click", "go_back", "click",...] I want to filter this data based on up to three inputs. If input ...

Resolving TypeScript error when importing images statically in Next.js

In order to enhance the performance of images in my nextjs app, I am working on image optimization. However, I encountered an issue stating: Cannot find module '/images/homeBg.jpg' or its corresponding type declarations. The image is actually st ...

What sets Import apart from require in TypeScript?

I've been grappling with the nuances between import and require when it comes to using classes/modules from other files. The confusion arises when I try to use require('./config.json') and it works, but import config from './config.json ...

Error: Incorrect Path for Dynamic Import

Recently, I've been trying to dynamically load locale files based on the locale code provided by Next.js. Unfortunately, every time I attempt a dynamic import, an error surfaces and it seems like the import path is incorrect: Unable to load translatio ...

Converting JSON to TypeScript with Angular Casting

I'm facing an issue detailed below. API: "Data": [ { "Id": 90110, "Name": "John", "Surname": "Doe", "Email": "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="472d282f2923282207202a262e2b ...

An issue occurred: The module failed to self-register at the specified path: '/node_modules/onnxruntime-node/bin/napi-v3/linux/x64/onnxruntime_binding.node'

Hey there, I'm trying to implement transformer js in my node js application using typescript. The code is located in a file named worker.js. const TransformersApi = Function('return import("@xenova/transformers")')(); const { CLIPVisionModel ...

What is the process for building .ts components within a Vue application?

Looking to update an old project that currently uses the 'av-ts' plugin and vue-ts-loader to compile .ts files as Vue components. The project is running on Vue 2.4.2, but I want to upgrade it to version 2.6.14. However, since 'vue-ts-loader& ...

Error thrown due to missing property in type '{}' when using TypeScript arrow function parameter

As outlined in the documentation for interfaces in TypeScript, An interface declaration serves as an alternative way to define an object type. I'm puzzled by the error I encounter in the following code snippet. My attempt is to restrict the object ...

Is there a better approach to verifying an error code in a `Response` body without relying on `clone()` in a Cloudflare proxy worker?

I am currently implementing a similar process in a Cloudflare worker const response = await fetch(...); const json = await response.clone().json<any>(); if (json.errorCode) { console.log(json.errorCode, json.message); return new Response('An ...

Dealing with problems related to types in React and TypeScript createContext

Struggling to pass the todos (initial state) and addNewTodo (methods) using React Context hook and typescript. Despite trying multiple solutions, errors persist. Partial generics do not cause issues in the context component, but I encounter the error Cann ...

Select a randomly generated number from an array, which dynamically updates every time the browser is refreshed

I recently completed a project in Angular that utilizes the TMDB API. The project is nearly finalized, but I have a desire to implement a change where the background image (backdrop_path) and other elements shift each time the browser is reloaded. Curren ...

How can we transfer a value from a parent component class to a child subclass?

In my TypeScript file, there are three classes within a single file. I am attempting to transfer a value from the MainComponent class to the TableContent class. I initially tried using super() inside the TableContent class which did not work, and then att ...

How to create Angular applications that are independent of their environment?

I am in the process of updating my codebase to ensure that the variables used will function correctly regardless of the environment. Angular's angular.json offers the option to include environment-specific configurations. I am also interested in findi ...

Code for Stripe Connect processed through AWS Amplify's authentication system

Within the structure of my Angular application, I have successfully integrated AWS Amplify with OAuth and Hosted UI, resulting in a seamless connection process. Specifically, when attempting to link with Google, I am directed back to an URL similar to http ...

What is the best way to update placeholders in Angular 8+?

I have a collection of items: a = ['apple', 'mango', 'grape', 'papaya', 'banana', 'cucumber']. An input element is present with a placeholder stating select from fruits (the array elements should ...

Using Angular2 Pipes to display raw HTML content

I am currently working on developing a custom pipe in Angular2 that is capable of outputting raw HTML. My goal is to take input with newlines and convert them into HTML line breaks. Can anyone guide me on how to display raw HTML from an Angular2 pipe? Bel ...

Trouble with Styling React-Toastify in TypeScript: struggling to adjust z-index in Toast Container

Currently in the process of developing a React application utilizing TypeScript, I have incorporated the React-Toastify library to handle notifications. However, encountering some challenges with the styling of the ToastContainer component. Specifically, ...