Components in Angular 4 that are loaded dynamically using attribute directives are enclosed within a <div> element

My goal is to dynamically generate components based on the configuration options, specifically creating a toolbar with different "toolbar items".

Following the Angular guide at: https://angular.io/docs/ts/latest/cookbook/dynamic-component-loader.html, I have implemented a dedicated directive:

@Directive({
    selector: '[mte-toolbar-item-host]'
})
export class ToolbarItemDirective {

    constructor(public viewContainerRef: ViewContainerRef) {
    }
}

This directive will serve as the insertion point for the components.

I also created the main ToolbarComponent:

@Component({
    selector: "mte-toolbar",
    templateUrl: "./toolbar.component.html",
    styleUrls: ["./toolbar.component.css"],
    providers: [ToolbarService]
})
export class ToolbarComponent implements AfterViewInit {
    toolbar: Toolbar;

    @ViewChild(ToolbarItemDirective)
    toolbarItemHost: ToolbarItemDirective;

    constructor(private toolbarService: ToolbarService, private componentFactoryResolver: ComponentFactoryResolver) {
    }

    ngAfterViewInit(): void {
        this.toolbar = new Toolbar(this.toolbarService.getToolbarItems());
        for (let i in this.toolbar.items) {
            let toolbarItem = this.toolbar.items[i];
            let toolbarItemFactory = this.componentFactoryResolver.resolveComponentFactory(toolbarItem.componentType);
            let componentRef = this.toolbarItemHost.viewContainerRef.createComponent(toolbarItemFactory);
            componentRef.instance.toolbarItem = toolbarItem;
        }
    }
}

The template for the ToolbarComponent includes an unordered list with injection points:

<ul class="nav nav-pills">
    <li role="presentation" mte-toolbar-item-host></li>
</ul>

The toolbarService currently provides a list of default components:

... 

GlyphToolbarItem and GlyphToolbarItemComponent classes were implemented to handle the toolbar items and their templates respectively. Here's how they are structured:

...

I anticipated the output to be rendered correctly within list elements, but instead, the dynamic components are wrapped in <div>. Is this behavior correct or is there a better way to achieve this?

Answer №1

It appears that you need to use GlyphToolbarItemComponent:

@Component({
    selector: 'li[mte-glyph-toolbar-item]',
    template: '<a class="btn btn-default btn-sm glyphicon {{toolbarItem.glyphIcon}}"></a>'
})
export class GlyphToolbarItemComponent {
  @HostBinding('attr.role') role ="presentation";
  toolbarItem: ToolbarItem;
}

Additionally, you should remove the empty list item and move mte-toolbar-item-host to a ng-container within a ul element.

<ul class="nav nav-pills">
  <ng-container mte-toolbar-item-host></ng-container>
</ul>

It is also worth noting that Angular may not approve of creating these components in ngAfterViewInit.

I have provided an example here: https://plnkr.co/edit/8cjlzooO1Oh2CWydxbSN?p=info

Answer №2

Regardless of the specific element you retrieve the ViewContainerRef reference from, createComponent will insert a sibling and utilize the selector of the dynamically generated component as the element. In cases where no element is specified in the selector, <div> is used by default.

If you modify the selector from

selector: '[mte-glyph-toolbar-item]',

to

selector: 'li[mte-glyph-toolbar-item]',

or

selector: 'li',

you will receive an <li> element.

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 access data within nested objects using ngFor in Ionic 4

How can I access the data I need from an API when it is nested within multiple objects? I am attempting to retrieve the full_url from the data object, which is nested inside the avatar object. I have already attempted the following: <ion-list> ...

Ways to display varied JSON information on a component in Angular 4

I am facing a challenge with a reusable component that fetches data from a JSON file. I want to customize the data displayed when this component is used as a subcomponent within other components. For example, let's say we have a Banana component: @U ...

Using TypeScript to chain observables in a service and then subscribing to them in the component at the end

Working with Platform - Angualar 2 + TypeScript + angularFire2 Within my user.service.ts file, I have implemented the following code to initiate an initial request to a firebase endpoint in order to fetch some path information. Subsequently, I aim to util ...

The issue with the react-diagram stemmed from a conflict with @emotion/core

During the installation of react-diagrams by projectStorm, I encountered some errors which are shown in the following image: errorImg Despite attempting to downgrade the version of '@emotion/core' to ^10.0.0, the issue persisted. Here is a view ...

Angular Igx-calendar User Interface Component

I need assistance with implementing a form that includes a calendar for users to select specific dates. Below is the code snippet: Here is the HTML component file (about.component.html): <form [formGroup]="angForm" class="form-element"> <d ...

How can I showcase array elements using checkboxes in an Ionic framework?

Having a simple issue where I am fetching data from firebase into an array list and need to display it with checkboxes. Can you assist me in this? The 'tasks' array fetched from firebase is available, just looking to show it within checkboxes. Th ...

Creating Algorithms for Generic Interfaces in TypeScript to Make them Compatible with Derived Generic Classes

Consider the (simplified) code: interface GenericInterface<T> { value: T } function genericIdentity<T>(instance : GenericInterface<T>) : GenericInterface<T> { return instance; } class GenericImplementingClass<T> implemen ...

Angular Reactive Forms may not properly update other inputs when binding a control to multiple inputs

While working with reactive forms, I encountered an issue where accessing the same control in multiple inputs seemed to result in one-way data binding (input-to-model). If I make edits in one input, it updates the model correctly but does not refresh the o ...

Issue when trying to use both the name and value attributes in an input field simultaneously

When the attribute "name" is omitted, the value specified in "value" displays correctly. However, when I include the required "name" attribute to work with [(ngModel)], the "value" attribute stops functioning. Without using the "name" attribute, an error ...

It is not possible to repeatedly hear the same event on a single element

It seems that I am unable to listen to an event multiple times on a single element. Upon investigation, I have found the following observations: This issue arises when triggering an RxJS observable from lifecycle methods such as ngAfterViewChecked, ngDoC ...

Parent component interacting with child component

In my application, I have a header component along with registration and login components. The selector of the header component is used in both the login and registration components. There is also a button in the header that displays as a login button if t ...

The npm build command is triggering an error message that reads "Allocation failed due to ineffective mark-compacts near heap limit."

I'm currently working on a ReactJS/TypeScript project on Windows 10. I've been running into issues when trying to build my TypeScript scripts using the following command: "rimraf ../wwwroot/* && react-scripts-ts build && copyfi ...

Efficient access to variable-enumerated objects in TypeScript

Let's say I have the following basic interfaces in my project: interface X {}; interface Y {}; interface Data { x: X[]; y: Y[]; } And also this function: function fetchData<S extends keyof Data>(type: S): Data[S] { return data[type]; } ...

Hide react component by clicking it

There is a cookies component with a button labeled "I agree" that I want to use to close the component when clicked. However, I am facing an issue in getting this functionality to work. I understand that the onClick event on the button should trigger an ...

What is the best way to retrieve TemplateRef from an Angular component?

TS Component ngOnInit() { if(somecondition) // The line of code that is causing issues this.openModal(#tempName); } HTML Component <ng-template #tempName> Content goes here! </ng-template> this.openModal(#tempNa ...

When setupFilesAfterEnv is added, mock functions may not function properly in .test files

Upon including setupFilesAfterEnv in the jest.config.js like this: module.exports = { preset: 'ts-jest', testEnvironment: 'node', setupFilesAfterEnv: ["./test/setupAfterEnv.ts"] } The mock functions seem to sto ...

There seems to be an issue with the compatibility between typescript and the current version (4.17.14) of the express-serve-static

Using "@types/express-serve-static-core": "4.17.13", the augmentation of express-serve-static-core is functioning properly: import { Request, Response, NextFunction } from 'express' import { PrismaClient } from '@prisma/c ...

Utilizing a method from a separate class in Ionic 2

Having trouble using the takePicture() function from camera.ts in my home.ts. I keep getting an error message saying "No provider for CameraPage!" Any assistance on how to resolve this issue would be greatly appreciated, as I am new to this language and ju ...

Having trouble dispatching a TypeScript action in a class-based component

I recently switched to using this boilerplate for my react project with TypeScript. I'm facing difficulty in configuring the correct type of actions as it was easier when I was working with JavaScript. Now, being new to TypeScript, I am struggling to ...

What is the best way to showcase several items in a slide with Ionic 2?

I am a beginner with Ionic 2 and I am trying to display multiple products in a single slide. While I have successfully displayed the slide, I am seeing small dots below the image. How can I remove these dots? Below is my HTML code: <ion-row class="bran ...