Modify html from typescript (Angular) - html

I try to modify a part of HTML in a component as we do with JS "innerHTML" in a angular app. I'm a beginner with angular, maybe I missed something important.
Actually look like that (typescript, html (from the same component)):
import { Component, OnInit, Input } from '#angular/core';
import { GraphService } from '../services/graph.service';
#Component({
selector: 'app-graph-content',
templateUrl: './graph-content.component.html',
styleUrls: ['./graph-content.component.scss']
})
export class GraphContentComponent implements OnInit {
#Input() graphName: string;
#Input() index: number;
#Input() id: number;
#Input() graphContent: any;
graphI:string;
constructor(private graphService:GraphService) { }
testF(){
var inputGraph = this.graphService.refreshGraph(this.graphContent);
//inputGraph should go in DOM and look like : "<div class=\"progress-fill\" style=\"background-color: black;\"><span>XX%</span></div>"
}
ngOnInit() {
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div class="list-group-item list-group-item-action flex-column align-items-start list-group-flush">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1"> {{ graphName }}</h5>
</div>
<div class="horizontal" style="height: 100px;">
<div class="progress-track" style="display: flex; flex-wrap: nowrap; justify-content: flex-start;" id="graphInput">
<!--here comes the content-->
</div>
<button (click)="testF()">react</button>
</div>
So inputGraph must go in graphInput div. Is there a simple way to do it, would it be better to create a component for this part?

You can use the property binding for innerHTML like [innerHTML].
<div [innerHTML]="htmlstring">
and in your component.ts file
this.htmlstring = `<p> Hello</p>`

¿What kind of data came from this.graphService.refreshGraph(this.graphContent)?
¿It´s JSON data?
Maybe you could make a component named app-input-graph, with an #Input inputGraph and this html code:
<div class="progress-fill" style="background-color: black;">
<span>{{inputGraph}}</span>
</div>
And in app-graph-content:
<app-input-graph [inputGraph]="inputGraph"><app-input-graph>

Related

how to display HTML with angular function?

I'd like to display formated HTML using type script function in an angular component, I wanted it to display question from diferent type, I tried this,
import {Component, OnInit} from '#angular/core';
import {TP, Question, Qtype} from "../tp";
import * as Exercice from '../assets/Exercice.json';
#Component({
selector: 'app-tp',
templateUrl: './tp.component.html',
styleUrls: ['./tp.component.css']
})
export class TpComponent implements OnInit {
constructor() {
}
ngOnInit(): void {
}
displayQCM(question: Question) {
return `
<div>
<hr class="w-100">
<h3>Question n°${question.number} ${question.questionType}</h3>
<p>${question.questionContent}</p>
...
QCM question element
...
</div>
`;
}
displayTrueOrFalse(question: Question) {
return `
<div>
<hr class="w-100">
<h3>Question n°${question.number} ${question.questionType}</h3>
<p>${question.questionContent}</p>
...
true or false question element
...
</div>
`;
}
displayQuestion(question: Question) {
return `
<div>
<hr class="w-100">
<h3>Question n°${question.number} ${question.questionType}</p>
<p>${question.questionContent}</p>
...
normal question element
...
</div>
`;
}
}
<div class="row justify-content-center">
<div class="col-12 col-lg-6">
<h2>Questions</h2>
{{displayQCM()}}
{{displayQuestion()}}
{{displayTrueOrFalse()}}
</div>
</div>
but the HTML display only as plain text writing fully the code on the page, do you know how to fix this ?
EDIT: edited code to be more in the context, the question comes from a json file and there's 3 type of them, I created a function to translate them into Question and depending on there type I want 3 way to display them in 3 different forms, each type as a long HTML development and are displayed with different tag and element
You need to use [innerHTML] property in your html file
<div class="row justify-content-center">
<div class="col-12 col-lg-6">
<h2>Questions</h2>
<div [innerHTML]="displayQCM()"></div>
<div [innerHTML]="displayQuestion()"></div>
<div [innerHTML]="displayTrueOrFalse()"></div>
</div>
</div>
If you are just trying to inject dynamic content you need to sanitize your html string and then use innerHtml. From your question Im not sure what the goal is and there must be a better way without injecting Html but you would need to clarify the goal.
questions: Array<SafeHtml> = new Array<SafeHtml>();
myJson: Array<string> = []; //I dont know where its coming from
constructor(private sanitizer: DomSanitizer) {
}
ngOnInit(): void {
myJson.forEach((question) => {
this.questions.push(this.sanitizer.sanitize(question));
})
}
<div class="row justify-content-center">
<div class="col-12 col-lg-6">
<h2>Questions</h2>
<div *ngFor="let q of questions" [innerHtml]="q"></div>
</div>
</div>
Why you don't use ngFor to list all questions?
HTML
<div class="row justify-content-center">
<div class="col-12 col-lg-6">
<h2>Questions</h2>
<div *ngFor="let question of allQuestions">
<hr class="w-100">
<h3>Question n°{{question.number}} {{question.questionType}}</h3>
<p>{{question.questionContent}}</p>
</div>
</div>
</div>
And allQuestions is your question array
You can add conditions depends on question type with *ngIf:
<p *ngIf="question.questionType=== 'normal'"></p>
or you can use ng-template:
<ng-template [ngIf]="question.questionType === 'normal'">Your HTML code for normal question</ng-template>
<ng-template [ngIf]="question.questionType === 'trueFalse'">Your HTML code for trueFalse question</ng-template>
Exemple
TS :
displayQCM : boolean;
displayQuestion : boolean;
displayTrueOrFalse : boolean;
HTML
<div class="row justify-content-center">
<div class="col-12 col-lg-6">
<h2>Questions</h2>
<div *ngIf="displayQCM">...</div>
<div *ngIf="displayQuestion">...</div>
<div *ngIf="displayTrueOrFalse">...</div>
</div>
</div>

Bootstrap Grid System not working in Angular Components communicating from parent to child

app.component.html code
<div class="container">
<div class="row" id="ads">
<div class="col-xs-4">
<app-card *ngFor="let car of cars"
[carNotifyBadge]="car.carNotifyBadge"
[carNotifyYear]="car.carNotifyYear"
[carCondition]="car.carCondition"
[carPrice]="car.carPrice"
[carUsageinKM]="car.carUsageinKM"
[carName]="car.carName"
[imgSource]="car.imgSource"
>
</app-card>
</div>
</div>
</div>
app.component.ts code
import { Component ,Input} from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title:string = "Angular-App"
cars = [
{....},{....},{....}
]
}
card.component.html
<div class="card rounded">
<div class="card-image">
<span class="card-notify-badge">{{carNotifyBadge}}</span>
<span class="card-notify-year">{{carNotifyYear}}</span>
<img class="img-fluid" [src]="imgSource" alt="Alternate Text" />
</div>
<div class="card-image-overlay m-auto">
<span class="card-detail-badge">{{carCondition}}</span>
<span class="card-detail-badge">{{carPrice}}</span>
<span class="card-detail-badge">{{carUsageinKM}}</span>
</div>
<div class="card-body text-center">
<div class="ad-title m-auto">
<h5>{{carName}}</h5>
</div>
<a class="ad-btn" href="#">View</a>
</div>
</div>
card.component.ts
import { Component, OnInit, Input } from '#angular/core';
#Component({
selector: 'app-card',
templateUrl: './card.component.html',
styleUrls: ['./card.component.css']
})
export class CardComponent implements OnInit {
constructor() { }
#Input() carNotifyBadge = '';
#Input() carUsageinKM = '';
#Input() carName = '';
#Input() carNoticarNotifyYearfyBadge = '';
#Input() imgSource = '';
#Input() carCondition = '';
#Input() carPrice = '';
#Input() carNotifyYear = '';
ngOnInit(): void {
}
}
Since in app.component.html I have used grid system of bootstrap and using structural directives ngFor I am dynamically adding elements to DOM. I expect the cols to be side by side, whereas I am getting it below each other as shown in the image.
How to display cols side by side as per bootstrap behaviour ?
Make sure bootstrap CSS is loaded in the application if not, follow these steps.
Steps to include Bootstrap in Application
Pass only car item to the child component, all properties within car object yu will be able to access in the child component.
<div class="container">
<div class="row" id="ads">
<div class="col-xs-6 col-md-4" *ngFor="let car of cars">
<app-card [car]="car"></app-card>
</div>
</div>
</div>
In the child component, receive the car object inputs from the parent component.
#Input car;
make sure, that bootstrap is included in your bundled.css file.
has '#ads' any styles which override bootstraps behavior?
helpful link for install bootstrap using-bootstrap-with-angular
I had similar problem. I use a bootstrap and a commercial theme built on it. I tried to present list of records in bootstrap grid.
I have main app-component which presents the web page. Then I have card-list component which presents grid list within app-component.
When I typed:
styleUrls: [
'./credential-card.component.css',
'../../assets/css/bootstrap.min.css',
'../../assets/css/style.css']
Cards were properly styled, but grid didn't work.
When I removed styles
styleUrls: [
'./credential-card.component.css']
I lost styling but grid worked fine.
What fixed the problem was to implement another component card-detail and invoke it from card-list. I removed bootstrap CSS from card-list, and added to card-detail.
Finally, I have something like this in card-list component:
<section class="pricing-wrapper pt-70 pb-100">
<div class="container">
<div class="row justify-content-center">
<div *ngFor="let item of credentials" class="col-lg-4 col-md-6 col-sm-8">
<card-detail [shortName]="item.payload.doc.data().shortName" [priceDescription]="item.payload.doc.data().priceDescription"></card-detail>
</div>
</div>
</div>
And this in card-detail:
<div class="pricing-style-5 mt-30">
<div class="pricing-header">
<div class="pricing d-flex align-items-center flex-wrap">
<h3 class="heading-3 font-weight-400 title">{{shortName}}</h3>
<span class="price">{{priceDescription}}</span>
</div>
</div>
</div>

Angular | Bootstrap - Modal not showing

<img id="1" data-toggle="modal" data-target="#myModal" data-dismiss="modal" src='assets/barrel.jpg' alt='Text dollar code part one.' />
<div id="myModal" class="modal fade" *ngIf="isModalShowing">
<div class=" modal-lg center">
<div class="modal-header">
<button type="button" class="close" (click)="toggleModal()">×</button>
<div class="modal-content">
<div class="modal-body">
<img id="1" src="assets/barrel.jpg" class="img-responsive">
<img id="2" src="assets/car.jpg" class="img-responsive">
</div>
</div>
</div>
</div>
</div>
Above is my html, nothing happens when I click on the image that I am using as my modal trigger. This started when I add the ngIf="isModalShowing" function. Below is my typescript.
import { Component, OnInit, ViewChild } from '#angular/core';
import { NgModule } from '#angular/core';
#Component({
selector: 'app-portfolio',
templateUrl: './portfolio.component.html',
styleUrls: ['./portfolio.component.scss']
})
export class PortfolioComponent implements OnInit {
constructor() { }
public ngOnInit() {
}
isModalShowing: boolean;
toggleModal() {
this.isModalShowing = !this.isModalShowing;
}
}
This might help you as you are using pure bootstrap.
pay attention to [ngClass] in app.component.html file
I added modal-backdrop class to the class list that gives a visual indication of an active modal.
https://stackblitz.com/edit/angular-jggbzx
Or else use ng-bootstrap that has better ways of doing this
Documentation
https://ng-bootstrap.github.io/#/components/modal/examples
Running Example
https://stackblitz.com/edit/angular-dwqv1u

Disable scrolling in typescript as soon as property is true

I have a hamburger inside of my header - as soon as it is clicked, I wan't to disable scroll - since the hamburger is moving on scroll.
I tried to set the hamburger to position: fixed. But this one changed the position of its neighbour, which looked weird.
Is there a way to realize this in typescript - so that as soon clicked is true, scrolling is disabled. Or is there a better approach?
https://stackblitz.com/edit/angular-beiajz
export class HeaderComponent implements OnInit {
clicked = false;
onClick(): void {
this.clicked = !this.clicked;
}
constructor() { }
ngOnInit(): void {
}
}
<div class="container-fluid mobile position-absolute">
<div class="row m-0 w-100">
<div class="col-6 offset-3 justify-content-center d-flex">
<a class="align-self-center" routerLink="">
<h1>NØREBRO STUDIOS</h1>
</a>
</div>
<div class="col-3">
<button class="hamburger hamburger--collapse" (click)="onClick()" [class.is-active]="clicked" type="button">
<span class="hamburger-box">
<span class="hamburger-inner"></span>
</span>
</button>
</div>
<div class="container-fluid position-fixed min-vh-100 px-0 slide-in" [class.get-active]="clicked">
</div>
</div>
</div>
One of the way is passing a event from the child to parent whenever click is made on the hamburger menu and changing the parent class CSS
in app.component.html
<app-test (hamburgerClick)="hamburgerClickEvent($event)"></app-test>
<div [ngClass]="{
'container-fluid-overlay': overlayFlag === true,
'container-fluid': overlayFlag === false }">
</div>
in app.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular';
overlayFlag = false; // overlay flag..onload overlay is hidden
public hamburgerClickEvent(e:boolean):void{
this.overlayFlag= e;
}
}
in app.component.css
.container-fluid {
min-height: 200vh;
}
.container-fluid-overlay {
height: auto;
}
in test.component.ts
import { Component, OnInit , Output, EventEmitter} from '#angular/core';
#Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.css']
})
export class TestComponent implements OnInit {
#Output() hamburgerClick = new EventEmitter();//emitter
clicked = false;
onClick(): void {
this.clicked = !this.clicked;
this.hamburgerClick.emit(this.clicked); //emitting clicked event to parent
}
constructor() { }
ngOnInit(): void {
}
}
Hope it helps :)

How to ovveride the css class of root component in its child component - Angular 2?

I have 3 components in angular 2 application.The class="container-fluid content" is css class in app.component.html. This class="container-fluid content" is default css for other components. Now I want to set background-color:blue in the detail component. I tried to set in detail.component.ts like this styles:['.container-fluid content{background-color: blue;}'] It did not work. If I set in app.component.html like this <div class="container-fluid content" style="background-color: blue;"> It applies to both the components. How to override this class="container-fluid content" in detail component?
//my project structure
app
- app.component.html
-app.component.ts
- welcome
-welcome.component.html
-welcome.component.ts
- detail
-detail.component.html
-detail.component.ts
//app.component.html
<div class="container-fluid content">
<router-outlet></router-outlet>
</div>
<app-footer></app-footer>
</div>
//welcome.component.html
<h1>welcome page heading</h1>
<div fxLayout="row" fxLayoutWrap style="padding-bottom: 25px;
padding-top: 25px; margin: auto;justify-content: center" >
<md-card>
<md-card-content>
<h1></h1>
<h2></h2>
<h2>
</h2>
</md-card-content>
</md-card>
</div>
//detail.component.html
<h1>Details page heading</h1>
<div fxLayout="row" fxLayoutWrap style="padding-bottom: 25px;
padding-top: 25px; margin: auto;justify-content: center" >
<md-card>
<md-card-content>
<h1></h1>
<h2></h2>
<h2>
</h2>
</md-card-content>
</md-card>
</div>
//detail.component.ts
import { OnInit, Component } from '#angular/core';
import { DetailService } from '../detail/detail.service';
import { HostBinding} from '#angular/core';
#Component({
providers: [DetailService ]
templateUrl: './detail.component.html',
styles: ['h3 {margin:5px}']
})
export class DetailComponent implements OnInit {
#HostBinding('class.blueClass') blue: boolean = false;
constructor( private _detailService: DetailService ) { }
ngOnInit() {
this.blue = true;
}
}
In child component, you can add this param to #Component.
// child-component.component.ts
#Component({
selector: 'child-component',
templateUrl: 'child-component.component.html',
styleUrls: ['child-component.component.css']
encapsulation: ViewEncapsulation.None
})
// child-component.component.css
.container-fluid content{background-color: blue;}
You can ref this side for more infomartion :
https://blog.thoughtram.io/angular/2015/06/29/shadow-dom-strategies-in-angular2.html
Have you tried with the hostbinding and adding a new class there?
#HostBinding('class.blueClass') blue: boolean = false;
And in the second component just switch that on onInit?
ngOnInit() {
this.blue = true;
}
The other way could be in the component definition, you can add the following line :
host: {'class': 'blueClass'}
and you do the rest of the css work in css instead.