Angular 2 Adding html dynamically to DOM, style not working [duplicate] - css

This question already has answers here:
Angular 2 - innerHTML styling
(11 answers)
Closed 5 years ago.
Hello I am trying to add html from a file that is returned from the api, this is working. what I am needing help with is when I add an inline style it doesn't work, but if I create a class in the style.css it and add it to the html it then works.
All of this said, I need to get inline style working. I would like to get <span style="color:red;">I am red</span> working.
#Component({
selector: 'my-app',
template: `
<div>
<h2>Hello {{name}}</h2>
<button (click)="onClick()">Click To Add Html</button>
</div>
<div *ngIf="html!==''" [innerHtml]="html"></div>
`,
})
export class App {
name:string;
html:string=null;
const htmlConst:string = `<span style="color:red;">I am red</span>`;
/*
I have tried [style] = "color:red;"
style="color:red;"
*/
constructor() {
this.name = `Angular! v${VERSION.full}`
}
onClick():void{
if(this.html !== ''){
this.html= this.htmlConst;
}
else{
this.html = '';
}
}
}
any advise would be helpful.

import { Component,ViewEncapsulation } from '#angular/core';
#Component({
selector: 'my-app',
template: `
<div>
<h2>Hello {{name}}</h2>
<button (click)="onClick()">Click To Add Html</button>
</div>
<div *ngIf="html!==''" [innerHtml]="html"></div>
`,
encapsulation: ViewEncapsulation.None
})
Please refer from https://toddmotto.com/emulated-native-shadow-dom-angular-2-view-encapsulation

Related

In Angular, can I add css style together with double curly brackets?

I am trying to create a style for my element using a variable name, which is a number, and adding % at the end. I am currently doing it inline like this:
<progress-bar
style="{{batteryLifeLeft+'%'}}"
/>
What is wrong with it? Can you not add things together in this expression? I am getting the error: "Property value expected" and "at-rule or selector expected."
Correct syntax would be [ngStyle]="{'width.%': batteryLifeLeft}". https://angular.io/api/common/NgStyle
<div style="width: {{ batteryLifeLeft }}%">
{{ batteryLifeLeft }}% this wont work
</div>
<br />
<div [ngStyle]="{ 'width.%': batteryLifeLeft }">
{{ batteryLifeLeft }}% this will work
</div>
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
batteryLifeLeft = 50;
constructor() {}
}
Working example is on StackBlitz

Why do the Bootstrap 4 elements reload entire Angular 7 application?

I am working with bootstrap 4 and angular 7, I have the following element, which function is to hide/show a sidebar.
<a
class="app-sidebar__toggle"
href="#"
data-toggle="sidebar"
aria-label="Hide Sidebar"
></a>
The problem is when I enter to specific route, this reloads all page. These are my routes in app-routing.module.ts
const routes: Routes = [
{ path: 'home', component: HomeComponent },
{ path: 'catalogo/lista', component: CatalogoListaComponent },
{ path: '', redirectTo: 'home', pathMatch: 'full' }
];
So, if I enter to http://localhost:4200/home, the error will happen, but if I enter to any other route (my default empty route will redirect to /home), for example, http://localhost:4200 or http://localhost:4200/a_route_that_not_exists, I am redirected to /home (as expected), and the button that show/hide the sidebar works well.
I hope to be clear in my problem and I would like a lot you can help me.
EDIT: More code of my application...
This is my app.component.html:
<app-header></app-header>
<app-sidebar></app-sidebar>
<div class="app-content">
<app-title [titulo]="titulo" [icono]="icono [breadcrumbs]="breadcrumbs"></app-title>
<router-outlet></router-outlet>
</div>
This is my header.component.html (where I use the link to show/hide the sidebar):
<header class="app-header">
<a class="app-header__logo" href="index.html">Vali</a>
<!-- Sidebar toggle button-->
<a
class="app-sidebar__toggle"
href="#"
data-toggle="sidebar"
aria-label="Hide Sidebar"
></a>
<p>.... more html</p>
</header>
And this is my sidebar.component.html:
<div class="app-sidebar__overlay" data-toggle="sidebar"></div>
<aside class="app-sidebar">
<div class="app-sidebar__user">
<img
class="app-sidebar__user-avatar"
src="https://s3.amazonaws.com/uifaces/faces/twitter/jsa/48.jpg"
alt="User Image"
/>
<div>
<p class="app-sidebar__user-name">John Doe</p>
<p class="app-sidebar__user-designation">Frontend Developer</p>
</div>
</div>
<ul class="app-menu">
<li>
<a class="app-menu__item" [routerLink]="['/home']">
<i class="app-menu__icon fa fa-home"></i>
<span class="app-menu__label">Inicio</span>
</a>
</li>
more menu elements...
<ul>
</aside>
Generally a lot of the Popper/ JS elements in Bootstrap won't work out of the box in Angular; Angular provides a pretty solid way to handle elements like sidenavs.
Since the element you want to use to toggle the sidenav doesn't exist in the same component as the sidenav, you can set up a basic service that handles the sidenav state. To create your sidenav service (run in console in your project root):
ng g s sidenav
And then in the generated sidenav.service.ts:
import {Injectable} from '#angular/core';
import {BehaviorSubject} from 'rxjs';
#Injectable()
export class SidenavService {
public isOpen: boolean = false;
public toggleChange: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
constructor() {}
public toggle(): void {
this.isOpen = !this.isOpen;
this.toggleChange.next(this.isOpen);
}
}
In your header.component.html you can modify the clickable element that will show/ hide the sidebar:
<a
class="app-sidebar__toggle"
aria-label="Hide Sidebar"
(click)="toggleSidebar()"
></a>
In your header.component.ts file you can then set toggleSidebar() to run the toggle() function in the service you just set up:
import {SidenavService} from "[wherever your service is located]";
#Component({ /*...*/ })
export class HeaderComponent {
constructor(private sidenavService: SidenavService)
toggleSidebar(): void {
this.sidenavService.toggle();
}
}
You can then (in either your app component or sidebar component) set up reacting to the toggle:
//assuming you're in sidebar.component.ts
import {SidenavService} from "[wherever your service is located]";
import {OnInit, OnDestroy} from "#angular/core";
import {Subscription} from "rxjs";
#Component({ /*...*/ })
export class SidebarComponent implement OnInit, OnDestroy {
isOpen: boolean;
sidenavSubscription: Subscription;
constructor(private sidenavService: SidenavService) {}
ngOnInit() {
this.sidenavSubscription = this.sidenavService.toggleChange.subscribe(isOpenChange => {
this.isOpen = isOpenChange;
});
}
ngOnDestroy() {
this.sidenavSubscription.unsubscribe();
}
}
You can then use the isOpen variable in your sidebar component in different ways to control sidebar activity. Examples include using an [ngClass] directive:
<!--in your header component-->
<header [ngClass]={'active': isOpen, 'inactive': !isOpen} >
</header>
Or you can build in something using angular animations to animate the sidebar in and out (using ngIf and the :enter/ :leave transitions).

Angular HTML class.otherclass explanation

I have seen this HTML line in an Angular project:
<div id="player" class="player" [class.voted]="booleanvar">
The CSS contains a defintion of .player.voted
I'm not really sure what this part means: [class.voted]="booleanvar"
This is one way of dynamically applying a class to an HTML element in Angular.
If booleanvar equates to true then the css class voted will be applied, so long as its defined correctly in CSS file. If it equates to false, then the class will not be applied.
<div id="player" class="player" [class.voted]="booleanvar">
I hope you help it
[class.voted]="booleanvar" this means the element add a class "voted" when "booleanvar" poperty or a variable value is true.
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
template:`
<div id="player" class="player" [class.voted]="booleanvar">
`
})
export class AppComponent {
booleanvar:boolean = true;
}
when booleanvar = false then the render element like '<div id="player" class="player">'
Otherwise it's render <div id="player" class="player voted">

Angular 'filter' style binding not work

There is an example
#Component({
selector: 'my-app',
template: `
<div>
<h2 style="background-color:green">
No Filter
</h2>
</div>
<div style="filter:brightness(0.5)">
<h2 style="background-color:green">
Filter with style.
</h2>
</div>
<div [style.filter]="'brightness(' + val + ')'">
<h2 style="background-color:green">
Filter with style binding.
</h2>
</div>
<p>filter binding express value: {{'brightness(' + val + ')'}}</p>
`,
})
export class App {
val = 0.5;
}
https://plnkr.co/edit/gD9xkX5aWrdNDyD6fnIh?p=preview
got the rendered result:
Seem like style binding [style.filter] not work. Anyone know the reason or give another way to control filter brightness style by component member value?
Thanks for any answer!
When we apply the filter style like this:
<div [style.filter]="'brightness(' + val + ')'">
the following message appears in the console:
WARNING: sanitizing unsafe style value brightness(0.5)
The style expression brightness(0.5) is considered unsafe by Angular. We can mark it as safe by calling DomSanitizer.bypassSecurityTrustStyle in a method of the component class or with the help of a custom pipe defined as:
import { Pipe } from "#angular/core";
import { DomSanitizer } from "#angular/platform-browser";
#Pipe({name: 'safe'})
export class SafePipe {
constructor(private sanitizer: DomSanitizer){
}
transform(style) {
return this.sanitizer.bypassSecurityTrustStyle(style);
}
}
which can be applied like this in the template:
<div [style.filter]="'brightness(' + val + ')' | safe">
An alternative, which does not involve sanitization problems, is to use the ngStyle directive:
<div [ngStyle]="{'filter': 'brightness(' + val + ')'}">
Both techniques are shown in this stackblitz.
The problem of unsafe style expressions has been discussed in other posts:
https://stackoverflow.com/a/38663363/1009922
https://stackoverflow.com/a/37267875/1009922

Angular 2 - same component with different text

I would like to use same component many times, but with different text. How can I do that?
My code:
jumbotron.component.html:
<div class="jumbotron text-center">
<h1 >{{jumbotronText}}</h1>
</div>
app.component.ts
#Component({
selector: 'my-app',
template: `
<navbar></navbar>
<jumbotron ></jumbotron>
<jumbotron ></jumbotron>
<jumbotron ></jumbotron>
`
,
directives: [NavbarComponent, JumbotronComponent]})
export class AppComponent { }
I tried do it like this:
<jumbotron [jumbotronText]="My text to display"></jumbotron>
And this:
<jumbotron jumbotronText="My text to display"></jumbotron>
But only got errors. I think that should be easy, but I cant find idea how to solve that.
First, you have to mark the jumbotronText with the Input() annotation in the Jumbotron component:
#Component({
selector: 'jumbotron',
template: `
<div class="jumbotron text-center">
<h1 >{{jumbotronText}}</h1>
</div>`
})
export class JumbotronComponent {
//here is important line
#Input() jumbotronText:string = "";
constructor() { }
}
Then, you can pass data in from the caller. If it is static text you can do this:
template: `
<navbar></navbar>
<jumbotron jumbotronText="One" ></jumbotron>
<jumbotron jumbotronText="Two" ></jumbotron>
<jumbotron jumbotronText="Three" ></jumbotron>`
And if it is calculated text you do:
template: `
<navbar></navbar>
<jumbotron [jumbotronText]="variableFromCaller1" ></jumbotron>
<jumbotron [jumbotronText]="variableFromCaller2" ></jumbotron>
<jumbotron [jumbotronText]="variableFromCaller3" ></jumbotron>`
That is, if you have variables in the app component which store the strings (or methods, or are somehow otherwise calcualted) you use square brackets to indicate one-way binding. Otherwise, if you have static text you just assign the Input() value the same as any other HTML tag property.
See this Plunker: https://embed.plnkr.co/ve31cnEDidcLeEF7dfVj/
You will either need to use #Input or ng-content. By using the {{ }} syntax you are telling Angular to look for a variable named jumbotronText in AppComponent, but that doesn't exist.
Using #Input()
jumbotron.component.html
<div class="jumbotron text-center">
<h1>{{ jumbotronText }}</h1>
</div>
jumbotron.component.ts
#Component({
// ...
}) export class JumbotronComponent {
#Input() jumbotronText: string;
// ...
}
app.component.ts
#Component({
selector: 'my-app',
template: `
<navbar></navbar>
<jumbotron [jumbotronText]="My text to display"></jumbotron>
`
,
directives: [NavbarComponent, JumbotronComponent]})
export class AppComponent { }
Using ng-content
jumbotron.component.html
<div class="jumbotron text-center">
<h1><ng-content></ng-content></h1>
</div>
app.component.ts
#Component({
selector: 'my-app',
template: `
<navbar></navbar>
<jumbotron>My text to display</jumbotron>
`
,
directives: [NavbarComponent, JumbotronComponent]})
export class AppComponent { }
Adding to Luke's answer. You must import the Input annotation from
#angular/core
When using the #Input() annotation on a property. You can add a string as a parameter to reference the property with an alias.
Example:
#Input("customTitle")
Private title:string;
You can later use
<my-directive [customTitle]="Custom" > </my-directive>

Resources