Changing HTML content dynamically using tabs within Angular 2 to create a stylish design

I'm working on developing a reusable angular2 component that can take an array of URLs linking to HTML files on my server. The goal is to generate a content window with tabs for switching between different "chapters", effectively swapping out the HTML and CSS within the content window. I've experimented with various approaches, such as iframes (which didn't work), deprecated ng-include workarounds from Angular 1 found on StackOverflow, and even building a component that allows inputting HTML but struggles with applying styles properly due to Angular stripping out style and script tags. Here's what I've attempted:

Within my parent component class:

htmlInput: string = "<h1>Why Does Angular make this so hard?</h1>";
cssInput: string = "h1 { color:red; }"

Parent Component HTML:

<app-html [html]='htmlInput' [css]='cssInput'></app-html>

My HTML Component:

import { Component, Input, OnInit } from '@angular/core';

@Component({
    selector: 'app-html',
    template: '<div [innerHtml]=html></div>', //This works but no style
    //template: '{{html}}', //This displays the actual markup on page
    styles: ['{{css}}'] //This does nothing
    //styles: ['h1 { color: red; }']//Also nothing
})
export class HtmlComponent implements OnInit {
    @Input() html: string = "";
    @Input() css: string = "";
    ngOnInit() {

    }
}

The code renders:

Why Does Angular make this so hard?

However, the red color isn't applied. It seems like the style might be processed before adding innerHtml to the DOM. Just using {{html}} displays the markup with visible h1 tags.

My aim is to easily flip through existing HTML pages stored on my server in a folder, all styled consistently and without reloading the entire page. Creating routes for each one would be cumbersome given the number of pages, and I prefer not to create individual routes for navigation. Any suggestions for embedding styled HTML dynamically with the latest version of Angular 2 (2.0.0-beta.17) are welcome. Alternatively, if there's a more Angular-friendly approach to achieve similar results, I'd appreciate hearing about it.

Thank you.

Edit:

To address my issue, I created a pipe to sanitize HTML before adding it to an iframe.

import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';

@Pipe({ name: 'safe' })
export class SafePipe implements PipeTransform {
  constructor(private sanitizer: DomSanitizer) {}
  transform(url: string) {
    return this.sanitizer.bypassSecurityTrustResourceUrl(url);
  }
}

This enables passing HTML into the iframe:

<iframe width="100%" height="1000" frameBorder="0" [src]="url | safe"></iframe>

This solution proves useful for displaying old pages containing jQuery and specific styles. It serves as a quick workaround for showcasing them.

Answer №1

When working with Angular 2, the styles added to a component are modified by including dynamically added attributes like _ngcontent-yle-18 into the CSS selectors.

This is done in order to mimic shadow DOM style encapsulation. However, these attributes are not applied to dynamically added HTML (such as through the use of innerHTML).

Possible Solutions

  • Embed styles directly in the index.html, as Angular 2 does not rewrite these styles

  • Set ViewEncapsulation.None to prevent Angular from adding the encapsulation emulation attributes

  • Use /deep/ to instruct Angular 2 to ignore the encapsulation emulation attributes

For more information, refer to Angular 2 - innerHTML styling

Answer №2

To optimize your CSS usage, consider encapsulating it within an object and utilizing the ngStyle directive for binding to your component instead of the styles attribute. This is because the styles attribute does not support data binding.

For instance:

htmlInput: string = "<h1>Why Does Angular make this so hard?</h1>";
cssInput: string = "{h1 { color:red; }}"

Parent Component HTML:

<app-html [html]='htmlInput' [css]='cssInput'></app-html>

Your HTML Component:

import { Component, Input, OnInit } from '@angular/core';

@Component({
    selector: 'app-html',
    template: '<div [innerHtml]="html" [ngStyle]="css"></div>',
    styles: []
})
export class HtmlComponent implements OnInit {
    @Input() html: string = "";
    @Input() css: string = "";
    ngOnInit() {

    }
}

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

JavaScript vs. markup: deciding between generating an extensive list of options or including them directly in

Recently, I encountered an issue with a .NET page that included a large number of identical dropdown lists within a repeater. Unfortunately, the rendering performance of the website was below expectations. In an attempt to improve the performance, I exper ...

Issues with PHP login session not being established when logging in with an SQL database

Lately, I've set myself a new challenge - creating a functional login screen for a website I'm building for my friends. However, despite inputting the email and password from my SQL database correctly, the validation file I'm using doesn&apo ...

Tips on utilizing boolean assignment in a ternary operator with an optional property that is an array in TypeScript

I'm trying to determine the value of an object property based on whether an optional prop is an array. Here's the scenario: const requestingMultipleDevices = Array.isArray(deviceIds); Then I have this object structure: { data: requestingM ...

Choose all the alternative A radio buttons utilizing JavaScript

If the "4 stars" option is selected at the top, I want all corresponding "4 stars" options in the form to be automatically selected. Similarly, if "3 stars" is chosen, I need all the "3 stars" options to be selected. I attempted to achieve this functionali ...

Steps to create an Executable from a complete Typescript project

My current project in Typescript consists of multiple folders and config files that are interconnected to form a larger script. I am looking for the best approach to compile it into an executable. Key points to consider: • Multiple Typescript files w ...

Create a Stylish Tilted Effect on Div Sides using CSS

I am attempting to create a specific shape using clip-path: polygon, but I am struggling to understand the documentation. The properties for this shape are unclear to me - what do the values represent in clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%) ...

Error: Unable to access the 'headers' property since it is null. MEAN stack issue

I'm in the process of developing a basic ToDoApp using the MEAN (Angular 2) stack, but I'm encountering an issue with the http.post request. Whenever I execute the post method, the current JSON object successfully gets added to the database. Howe ...

Numerous attributes housed within a single element

In my project, I have set up a Store using Angular and NgRx 13. Within my SharedModule, I define components including selectors which load content into the store to prevent redundant API calls. https://i.stack.imgur.com/sr3nl.png This approach is impleme ...

Insert the picture into an HTML document and retrieve the image file location

I successfully used <input type="file" accept="image/*"> to upload an image and then applied base64 encoding of the image in the onload callback function of a FileReader instance. However, I encountered a problem when trying to assign this base64 enc ...

How can I ensure perfect center alignment in CSS?

Is there a preferred method for centering elements using CSS? <div style="position: absolute; left: 50%;"> <div style="position: relative; left: -50%"> Centered content </div> </div> or simply <div style=" ...

Uncover the HTML tag associated with specific text on a webpage with the help of selenium

<div class="searchSummary floatL"> <span>18</span> results for "gloves" </div> Can someone assist me in using Selenium to extract the 'span' tag containing '18'? I am trying to specifically retrieve the 'sp ...

Is there a way for me to adjust the image dimensions so that it doesn't surpass the width of its parent container?

When working with images, it can be tricky to set the original width while also ensuring it fits within a parent container. For example, if the parent container has a width of 1000px, you may want the image to have a max-width of 100%, but not exceed 1000p ...

Mastering the art of calculating month differences on TypeScript dates in an Angular environment

Currently, I am working with Angular 7. Suppose I have a fixed rate X, for example, an amount I need to pay each month. Now, if I have two specified dates startDate and endDate, I want to calculate the total payment due for this given time period. To prov ...

Ways to conceal elements when a webpage is displayed in a pop-up window

JavaScript // Open popup window $('a.popup').click(function(){ window.open( this.href, 'Page title', 'width=600, height=650' ); return false; }); HTML snippet <a class="popup" href="sample.html"> In order to ...

The improper utilization or replacement of Jest mock in an Angular standalone component's unit test is causing issues

Presented here is a streamlined Ionic/Angular component with unnecessary code removed. import { IonicModule, ModalController } from '@ionic/angular'; @Component({ selector: 'my-component', templateUrl: 'my-component.html' ...

Bug in Chrome (Win) causing middle-mouse-button overflow issue

Take a look at this demo: http://jsfiddle.net/pixelfreak/AN5Wb/ Everything works perfectly until attempting to scroll using the middle mouse button. At that point, you can see beyond the boundaries of the element. This issue does not occur in Firefox or ...

What is the proper way to incorporate a backend variable within an EJS script block?

<!-- begin snippet: js hide: false console: true babel: false --> <script> // initializing the map var map = L.map('map').setView([25.037393872113785, 121.56372070312499], 12); // loading a tile layer var baseLayer = L ...

Is it possible to create a dynamic zig-zag design with CSS that

I am looking to design a dynamic snake/zigzag layout that consists of square images and circles, starting from the center of the container and descending in a winding fashion. The number of elements is not fixed and is generated based on data received fro ...

I can't understand why my body width is so disproportionately larger than usual

https://i.stack.imgur.com/jbeyI.png Encountering a new issue now. The width of my body is unusually high and I can't seem to identify the cause. I have included the code below. Tried adjusting margins but no luck. Searched for solutions online wi ...

Triggering an animation on one element by hovering over a different element

I'm trying to create a cool effect where the train ticket rotates when I hover over a leaf. Although I can get the train ticket to rotate when I hover over it directly, it doesn't seem to work when I hover over the leaf. Can someone help me spot ...