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>
Related
Hi i have the project with spring boot, sql, angular. I have relations with one to many and I dont know how to display the second object in component html.
My Componnent:
#Component({
selector: 'app-project',
templateUrl: './project.component.html',
styleUrls: ['./project.component.css']
})
export class ProjectComponent implements OnInit {
public project: Project[]=[];
public editProject!:Project;
public deleteProject!:Project;
public teams!:Teams[];
title:any;
constructor(private projectService: ProjectService, private _rotue:Router) { }
ngOnInit(): void {
this.getProject();
}
public getProject(): void {
this.projectService.getProject().subscribe(
(response) => {
this.project = response;
console.log(this.project);
},
(error: HttpErrorResponse) => {
alert(error.message);
}
);
My Html:
<div *ngFor="let projects of project" class="cards">
<div class="card m-b-30">
<div class="card-body row">
<div class="col-1">
</div>
<div class=" card-title align-self-center mb-0">
<h5>Name of Project: {{projects?.name}}</h5>
<p class="m-0">Name of team: {{projects?.teams.name}}</p>
</div>
My Json get:
{
"id":"34,
"name":"Projekt",
"priority":"wysoki",
"teams":[{
"id":2,
"name":"DruzynaA",
"leader":"Wojtek"
}]}
And the "teams" does not display, if i change that to project.teams is display [object Object]
also i try with | async but it not helped.
I am asking for help, I will be grateful
It looks like Teams is an array so you need to specify an index.
<p class="m-0">Name of team: {{projects?.teams[index].name}}</p>
Also, some notes.
you are using ngfor for project which looks like an object. you probably meant to do it for Teams?
Try this
Component:
public projects: Project[]=[];
Html:
<div *ngFor="let project of projects" class="cards">
<div class="card m-b-30">
<div class="card-body row">
<div class="col-1">
</div>
<div class=" card-title align-self-center mb-0">
<h5>Name of Project: {{project?.name}}</h5>
<ng-container *ngFor="let team of project.teams">
<p class="m-0">Name of team: {{ team.name }}</p>
</ng-container>
</div>
ngFor is used for iterables such as arrays. In your Object, 'teams' is the array where ngFor could be made use of. Try this.
<div class="cards">
<div class="card m-b-30">
<div class="card-body row">
<div class="col-1"></div>
<div class="card-title align-self-center mb-0">
<h5>Name of Project: {{ project?.name }}</h5>
<p class="m-0" *ngFor="let team of project.teams">
Name of team: {{ team.name }}
</p>
</div>
</div>
</div>
</div>
Note: However, if there is a number of teams that you want to display, go with an index for teams.
This is my parent component.
<div class="o-tile-container ">
<div *ngFor="let country of Countrys">
<app-country
[name]="name"
[count]="count"
[level]="'Country'"
></app-country>
</div>
</div>
This is my common country child component Html code
<div [matRippleColor]="primary" class="m-tile" matRipple>
<div class="a-tile-graph">
<div class="titles">
<div class="head" id="heading-name">{{name}}</div>
<div class="sub">{{level}}</div>
</div>
</div>
<div class="content-tile">
<div class="o-tile-content">
<div class="a-tile-title">{{name}}</div>
<div class="a-tile-count">{{count}}</div>
</div>
</div>
</div>
This kind of a thing.
In here i want to display heading-name in the same level of every tile and level country in a same level from top in every container. How can i do this?
To align text dynamically you can pass your style as #Input I have a sample code for you what exactly you want. Please check my code and demo code in stackblitz Demo LINK StackBlitz=>
** Parent HTML:**
<div class="o-tile-container ">
<div *ngFor="let country of Countrys">
<app-country
[name]="country.name"
[count]="country.count"
[level]="country.level"
[mystyle]="country.style"
></app-country>
</div>
</div>
Child HTML:
<div style="border-style: solid;width:100px" [matRippleColor]="primary" class="m-tile" matRipple [ngStyle]="this.mystyle">
<div class="a-tile-graph" >
<div class="titles">
<div class="head" id="heading-name" >{{name}} </div>
<div class="sub">{{level}}</div>
</div>
</div>
<div class="content-tile">
<div class="o-tile-content">
<div class="a-tile-title">{{name}}</div>
<div class="a-tile-count">{{count}}</div>
</div>
</div>
</div>
TS:
Parent TS:
export class AppComponent {
Countrys:any=[];
rippleColor: string = "white";
constructor(){
let c1=new Country();
c1.count=1;
c1.level='L1';
c1.name='A';
c1.style={'text-align':'center'}
this.Countrys.push(c1);
let c2=new Country();
c2.count=2;
c2.level='L2';
c2.name='B';
c2.style={'text-align':'right'};
this.Countrys.push(c2);
let c3=new Country();
c3.count=3;
c3.level='L3';
c3.name='C';
c3.style={'text-align':'left'};
this.Countrys.push(c3);
}
}
class Country{
name;string;
count:number;
level:string;
style:any;
}
Child TS:
export class CountryComponent implements OnInit {
#Input() level:string;
#Input() name:string;
#Input() count:number;
#Input() mystyle:any;
constructor() {
}
ngOnInit() {
}
}
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>
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>
I'm just starting at Angular.
I'm building a component; its footer and header should be visible only if these parameters are passed in.
panel.component.ts:
export class PanelComponent implements OnInit {
#Input() alignment = 'center';
#Input() color = '';
#Input() header = '';
#Input() footer = '';
panel.component.html:
<!--Panel-->
<div class="card" style="width: 22rem;" [ngClass]="(alignment==='left')?'text-left':(alignment==='right')?'text-right':'text-center'">
<div class="card-header {{color}} white-text" ng-if="!header===''">
</div>
<ng-content></ng-content>
<div class="card-footer text-muted {{color}} white-text ng-if="!footer===''" ">
<p class="mb-0">{{footer}}</p>
</div>
</div>
<!--/.Panel-->
html:
<panel color="success-color">
<div class="card-body">
<h4 class="card-title">Special</h4>
<p class="card-text">Check it out!</p>
</div>
</panel>
The problem is, no matter what I pass in for header or footer in my html, they actually get rendered; not passing anything just makes the top and bottom divs empty, but existing.
What am I missing? Pls halp
Love, Paco
Issue is here :
ng-if="!footer===''" "
First Issue :
use *ngIf not ng-if
Second :
"!footer===''" " should be "footer!==''" or "!(footer==='')"