Styles cannot be applied to elements that are dynamically generated

I am currently working on a project in Angular 9.1.13, hosted on Centos 7.

One of the components in my project contains static HTML code, shown below:

<ul id="myUL">
   <li><span class="caret">Top 1</span>
      <ul class="nested">
         <li>Sub 1</li>
         <li>Sub 2</li>
      </ul>
   </li>
</ul>

The CSS styling for this component is as follows:

ul, #myUL {
  list-style-type: none;
}

#myUL {
  margin: 0;
  padding: 0;
}

.caret {
  cursor: pointer;
  user-select: none;
}

.caret::before {
  content: "\25B6";
  display: inline-block;
  margin-right: 6px;
}

.caret-down::before {
  transform: rotate(90deg);
}

.nested {
  display: none;
}

.active {
  display: block;
}

In the ngOnInit() method of the component, the following JavaScript code is executed:

...
const toggler = document.getElementsByClassName('caret');
let i;
     
for (i = 0; i < toggler.length; i++) {
   toggler[i].addEventListener('click', function() {
      this.parentElement.querySelector('.nested').classList.toggle('active');
      this.classList.toggle('caret-down');      
   });
}
...

Although everything works well with the pre-defined HTML structure, issues arise when trying to dynamically generate the list content.

To achieve dynamic content generation, the HTML structure is modified as follows:

<ul id="myUL"></ul> <!-- intentionally left empty -->

Prior to the mentioned code within the ngOnInit(), the following snippet is added:

...
const myUL = document.getElementById('myUL');

myUL.innerHTML = 
   '<li><span class="caret">Top 1</span><ul class="nested"><li>Sub 1</li><li>Sub 2</li></ul></li>';

// Continue executing the previous code
...

Trouble arises from the fact that the dynamic content does not retain collapsible functionality or proper styling, despite having click events properly attached to the relevant elements:

My goal is to dynamically generate the list while maintaining the same interactive behavior and style seen in the initial screenshot.

Answer №1

Disclaimer: The following information is relevant only if you are specifically required to inject HTML as a string. For instance, when receiving the string from an API. In general, it is recommended to utilize Angular directives for generating content dynamically.

In Angular, View Encapsulation is implemented to ensure component-specific styling. This is achieved by assigning a unique identifier as an attribute to all HTML elements within the component, typically denoted as _ngcontent-nxs-c94="". Subsequently, this identifier is appended to CSS declarations within the component using [_ngcontent-nxs-c94]. By inspecting your elements, you can observe this process.

If HTML injection occurs post-compilation of the component, the injected HTML will not possess the unique attribute, resulting in unaffected CSS styles. While injecting HTML directly is discouraged due to Angular's dynamic content generation capabilities, should it be necessary, global CSS application (without the unique attribute) is recommended. Files specified in the styles array within angular.json are compiled as global styles, with styles.css serving as the default file.

To apply global styles, simply add your CSS to a file included in the styles array, such as styles.css, or create a new file adjacent to your original CSS file. However, caution must be exercised to ensure unique selectors, possibly by encapsulating all CSS within the component's HTML tag and incorporating additional unique class names for nested components to prevent unintended style conflicts.

Incorporating Global Styles into a Component

app-my-component {
  ul,
  #myUL {
    list-style-type: none;
  }

  #myUL {
    margin: 0;
    padding: 0;
  }

  .caret {
    cursor: pointer;
    user-select: none;
  }

  .caret::before {
    content: "\25B6";
    display: inline-block;
    margin-right: 6px;
  }

  .caret-down::before {
    transform: rotate(90deg);
  }

  .nested {
    display: none;
  }

  .active {
    display: block;
  }
}

This approach facilitates the application of global styles to a component while upholding view encapsulation within the original CSS file. Alternatively, disabling view encapsulation for the component is possible but not advisable, as it may inadvertently impact other components that require encapsulated styling.

Disabling View Encapsulation (not recommended)

@Component({
  selector: 'app-one',
  templateUrl: './one.component.html',
  styleUrls: ['./one.component.scss'],
  encapsulation: ViewEncapsulation.None
})
export class OneComponent {
  ...
}

By opting for this method, ./one.component.scss will be treated globally akin to files listed in the styles array. Before proceeding with this approach, ensure that the CSS modifications do not adversely affect other components.

Answer №2

To ensure proper styling for custom elements, it is recommended to utilize ng-deep and turn off scoped styles.

#myUL ::ng-deep {
  .caret {
    cursor: pointer;
    user-select: none;
  }

  .caret::before {
    content: "\25B6";
    display: inline-block;
    margin-right: 6px;
  }

  .caret-down::before {
    transform: rotate(90deg);
  }

  .nested {
    display: none;
  }

  .active {
    display: block;
  } 

}

Answer №3

If you want to create a dynamic list in your HTML using Angular, you can set up a caret object/list in your component and utilize *ngFor and [ngClass] to achieve the desired functionality. Here's an example:

component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent {
  carets = [
    {
      name: 'Top 1',
      children: [{ name: 'Sub 1' }, { name: 'Sub 2' }],
      toggle: false,
    },
    {
      name: 'Top 2',
      children: [{ name: 'Sub 1' }, { name: 'Sub 2' }],
      toggle: false,
    },
  ];
}

component.html

<ul id="myUL">
  <li *ngFor="let caret of carets" [ngClass]="caret.toggle ? 'active' : ''" >
    <span
      class="caret"
      [ngClass]="caret.toggle ? 'caret-down' : ''"
      (click)="caret.toggle = !caret.toggle"
      >{{ caret.name }}</span
    >
    <ul [ngClass]="caret.toggle ? '' : 'nested'">
      <li *ngFor="let child of caret.children">{{ child.name }}</li>
    </ul>
  </li>
</ul>

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

Unable to properly display date formatting in AG-Grid using the Angular date pipe

Currently, I am utilizing ag-grid in conjunction with Angular 8. Within my table, there is a column where my intention is to exhibit dates in a concise format. In order to achieve this, I opted to utilize the Angular date pipe. However, it appears that the ...

Leveraging enum types in Angular2 pipes

My current filter Pipe looks like this: import { Pipe, PipeTransform } from '@angular/core'; import { TaskStatus } from './task-status'; @Pipe({name: 'WithStatus'}) export class TaskStatusFilter implements PipeTransform{ ...

I am experiencing a problem with using the .focus() method with an input field

When my window loads, I want the cursor in this input to be blinking and ready for typing. I have tried using jQuery to make this happen, but for some reason I can't get the .focus() function to work properly. Check out my code on JSFiddle This is t ...

Develop a chart featuring sub-categories and column headings

I'm in the process of creating a table with subcategories and headers that resembles the image provided below: Here's what I've come up with so far: <table> <thead> <tr> <th>Item</th> & ...

MPDF does not support certain types of characters

When utilizing MPDF to generate a PDF, it may fail if it comes across certain characters such as this one: < (lower than). I attempted to configure MPDF by setting: $this->ignore_invalid_utf8 = true; and $this->allow_charset_conversion = false ...

Tips for Embedding React into a Specific ID using Hooks on an HTML Document

I am currently diving into the world of React hooks. While I understand class components, Hooks seem to be missing a specific render section. When adding React to a webpage (without using CREATE REACT APP), how do I specify where my hook should run on the ...

Unusual behavior encountered while attempting to reset input text using AngularJS

I'm encountering an issue with what I assumed would be a straightforward scenario. Here is the form in question: <form class="form-inline" role="form"> <div class="form-group"> <input type="text" ng-model="customerInput" size="80 ...

OnHover in CSS: Modify the properties of another element in addition to its own

Currently, I am working on developing a collapsible sidebar menu for my project. The objective is to have the text displayed when hovering over it and hidden when not in use. While I have found solutions for changing properties of other elements upon hover ...

Python Script to Extract Hyperlinks from HTML Documents

I am in the process of developing a Python script to extract the iframe src from a given set of websites. For example, if my input includes A.com, B.com, and C.com, and each of these sites has iframes linking to D.com, E.com, F.com (or 'None' if ...

What causes a custom element to suddenly crumble?

I am attempting to create a custom field that can display either an SVG or a Canvas, but the rendering is not as expected. I anticipate two boxes that are 400 pixels wide and 300 pixels high, however, they appear to collapse in an unusual manner. How can I ...

I prefer children to have their own unique style, instead of inheriting their parent's CSS

I currently have a project structured in the following way: There is an index page with a full layout Separate PHP files that are included in the index page Bootstrap is used in the index page, however, in some of the separate PHP files I also use jqgri ...

Issue with React Component: Radio Button Background Does Not Change on Initial Click

Currently, I am developing a React form where my goal is to dynamically change the background color of a label when a radio button is selected. However, upon clicking or checking the button, it seems that the state needs to be updated first before displayi ...

Is there a specific event or callback in MSAL-Angular that can be triggered upon completion of the signup process

Incorporating MSAL-Angular into our application, we are curious if there is an event or callback that triggers once a user successfully signs up, similar to the "msal:loginSuccess" event. ...

What is preventing me from displaying a jqGrid on my HTML page?

I am encountering some issues while trying to display a jqGrid on an HTML page. The code I have implemented is causing a run-time error, and the grid is not being loaded properly. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http:/ ...

How can I fix the issue of the onClick function in my React list not activating the toggle?

How to Activate Toggle Functionality Currently, I am working on a project using React where I developed a list with active states. I have implemented the onClick functions, but unfortunately, they are not working as intended. When I click on the list item ...

What is the process for making a nested ordered list in HTML?

How can I efficiently create a nested list structure like the one shown below, using nested JSON objects: Parent 1     a. Sub 1     b. Sub 2          i.Sub Sub 1 ...

Obtain span value using a CSS selector in Python

I need help extracting the value of a span using a CSS selector soup = BeautifulSoup("<body><main><div class='rentalprice'><span>3.000</span></div></main></body>") pagecontent = soup.find( ...

"Troubleshooting: jQuery functionality not functioning within the body of an Angular

Currently, I am utilizing jQuery to load gapi for my application's functionality in order to allow users to log out using their Google+ account. Although I have loaded jQuery in the head section of my index.html file, it appears that it is not being r ...

python code to locate element using selenium

Currently, I am utilizing selenium in conjunction with Python to automate tasks. I am facing an issue where I have a checkbox element that I need to click on, but the only information I have about it is the text it contains. The text is located within a &l ...

Describe the appearance of an element using CSS, rather than HTML

Currently encountering an issue, but unsure of the cause. My HTML page has image links like this: <span class="tribar" onclick="openNav()"><img src="url_here"></span> I attempted to remove all image URLs from the HTML code and place th ...