NgFor doesn't display data - html

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.

Related

Angular associate json value to img path

I have to display data that comes from an api that works well, I need to display each country with its corresponding flag but I don't understand how to associate the value of a json with the path of an image.
example : for the
libelle: Cambodge bigramme: KH
display: src/assets/flags/KH.jpg
libelle: France bigramme: FR
display: src/assets/flags/FR.jpg
I have tried to be as clear as possible.
thank you.
json
"drapeaux": [
{
"id": 1,
"mnemo": "KHM",
"libelle": "Cambodge",
"bigramme": "KH"
},
{
"id": 2,
"mnemo": "KHM",
"libelle": "France",
"bigramme": "FR"
}
]
}
service
getAll(): Observable<Ipost[]> {
return this.http.get<Ipost[]>(this.api);
}
components.ts
getAllNations() {
let resp = this.homeService.getAll();
resp.subscribe(result => {
this.postArray = result;
});
}
html
<div class="col-12">
<mat-card>
<div class="row">
<div class="col-1" *ngFor="let post of postArray">
{{post.libelle}}
<img [src]="post.bigramme.jpg" alt="flag">
</div>
</div>
</mat-card>
</div>
You have two options:
Option 1: In your service:
getAll(): Observable<Ipost[]> {
return this.http.get<Ipost[]>(this.api).pipe(
map(p => ({
...p,
bigramme: `src/assets/flags/${p.bigramme}.jpg`
}))
)
}
And then your Component's html:
<div class="col-12">
<mat-card>
<div class="row">
<div class="col-1" *ngFor="let post of postArray">
{{post.libelle}}
<img [src]="post.bigramme" alt="flag">
</div>
</div>
</mat-card>
</div>
Option 2: Or you can change only your Component's html:
<div class="col-12">
<mat-card>
<div class="row">
<div class="col-1" *ngFor="let post of postArray">
{{post.libelle}}
<img src="src/assets/flags/{{ post.bigramme }}.jpg" alt="flag">
</div>
</div>
</mat-card>
</div>

How to align texts dynamically in Grid tile container in Html in Angular

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() {
}
}

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>

how do i get the length of an array that is inside an object in angular from the html or ts?

what i trying to get from the console:
https://i.ibb.co/LtcCZfY/Untitled.png
this what i try to do in the html but no luck
<div class="cell" *ngFor="let s of allShips">
<h3>{{s.name}}</h3>
<span>{{s.passenger.length}}</span>
allShip.ts
allShips: Ship[];
constructor(private shipService: ShipService) { }
ngOnInit(): void {
this.shipService.getAllShips().subscribe(
(ships)=>{
this.allShips = ships;
console.log(ships);
// console.log(ships['passenger[0]'].length);
},
(err)=>{
alert(err);
}
)
}
allShips.html
<div class="grid">
<div class="cell" *ngFor="let s of allShips">
<h3>{{s.name}}</h3>
<span>{{s.passenger.name}}</span>
</div>
</div>
Try this:
<div class="grid" *ngIf="allShips | async as ships">
<div class="cell" *ngFor="let s of ships">
<h3>{{s.name}}</h3>
<span>{{s.passenger.name}}</span>
</div>
</div>
Wrap your for loop with a container to make sure allShips is initialized by the time ngFor runs:
<ng-container *ngIf="allShips">
<div class="cell" *ngFor="let s of allShips">
<h3>{{s.name}}</h3>
<span>{{s.passenger.length}}</span>
</div>
</ng-container>

How to add Row after every 3 columns in angular

What i am trying to do is add a row div after every 3 colum divs
Example Output need:
<div class="row">
<div class="col-md-6"></div>
<div class="col-md-6"></div>
<div class="col-md-6"></div>
</div>
I have an array of products i am iltrating like this
<div class="row" *ngFor="let p of relatedProperties;let i = index">
<div class="col-md-6" *ngIf="relatedProperties[i].title !== undefined">{{ relatedProperties[i].title }}</div>
<div class="col-md-6" *ngIf="relatedProperties[i].title !== undefined">{{ relatedProperties[i].title }}</div>
<div class="col-md-6" *ngIf="relatedProperties[i].title !== undefined">{{ relatedProperties[i].title }}</div>
</div>
But the problem is that my every row prints same title on one iltration and second on next iltration
Current output
<div class="row">
<div class="col-md-6">Title1</div>
<div class="col-md-6">Title1</div>
<div class="col-md-6">Title1</div>
</div>
<div class="row">
<div class="col-md-6">Title2</div>
<div class="col-md-6">Title2</div>
<div class="col-md-6">Title2</div>
</div>
<div class="row">
<div class="col-md-6">Title3</div>
<div class="col-md-6">Title3</div>
<div class="col-md-6">Title3</div>
</div>
Desired Output
<div class="row">
<div class="col-md-6">Title1</div>
<div class="col-md-6">Title2</div>
<div class="col-md-6">Title3</div>
</div>
<div class="row">
<div class="col-md-6">Title4</div>
<div class="col-md-6">Title5</div>
<div class="col-md-6">Title6</div>
</div>
<div class="row">
<div class="col-md-6">Title7</div>
<div class="col-md-6">Title8</div>
<div class="col-md-6">Title9</div>
</div>
If you split your Array into subarrays with always 3 titel's then you can easy loop through this Array in your template.
https://ng-run.com/edit/zZsztdvTOTpzbUC5Buuj?open=app%2Fapp.component.ts
component html
<div class="row" *ngFor="let row of newTitleArr; let i = index">
<div class="col" *ngFor="let col of newTitleArr[i]">{{ col.title }}</div>
</div>
component ts
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
titleArr = [
{ title: 'title1' },
{ title: 'title2' },
{ title: 'title3' },
{ title: 'title4' },
{ title: 'title5' },
{ title: 'title6' },
{ title: 'title7' },
{ title: 'title8' },
{ title: 'title9' },
{ title: 'title10' },
{ title: 'title11' },
{ title: 'title12' },
{ title: 'title13' },
];
newTitleArr:any[];
ngOnInit() {
this.newTitleArr = this.splitArr(this.titleArr, 3)
}
splitArr(arr, size) {
let newArr = [];
for(let i = 0; i< arr.length; i += size) {
newArr.push(arr.slice(i, i+size));
}
return newArr;
}
}
Maybe this works, but Im unsure
<ng-container *ngFor="let p of relatedProperties; let i = index">
<div class="row" *ngIf="(i + 1) / 3 === 1">
<div class="col-md-6" *ngIf="relatedProperties[i - 2].title != null">{{ relatedProperties[i].title }}</div>
<div class="col-md-6" *ngIf="relatedProperties[i - 1].title != null">{{ relatedProperties[i].title }}</div>
<div class="col-md-6" *ngIf="relatedProperties[i].title != null">{{ relatedProperties[i].title }}</div>
</div>
</ng-container>
Also, I gotta say this feels pretty hacky, but if this is what you request, this should work
edit:
Note that strict null (a == null) is better than checking for undefined (a === undefined), as it will check for both undefined or null. In your case title != null.
Also, you could build an iterable that holds the structure you want in a cleaner way.
instead of having [title1, title2, title3, title4, title5, title6...] you should try to have [[title1, title2, title3], [title4, title5, title6], ...] which is way cleaner and allows you to simply have two *ngFors inside your template
<element1 *ngFor="let innerArray of myArray; let i = index">
<element2 *ngFor="let title of innerAray; let j = index">
</element2>
</element1>
And finally, I suggest you avoid calling a variable 'p', that's bad practice.
You can use this to add a row after every 3 columns.
<ng-container *ngFor="let p of relatedProperties; let i = index">
<div class="row" *ngIf="(i%3)==0">
<div class="col-md-6" *ngFor="let p of relatedProperties.slice(i, i+3)>
<span *ngIf="relatedProperties[i].title !== undefined"> {{ relatedProperties[i].title }} </span>
</div>
</div>
</ng-container>