How to add Row after every 3 columns in angular - html

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>

Related

NgFor doesn't display data

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.

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>

Angular animate query returning zero elements

Using Angular, I wanted to make an animated display list. The problem is that I am getting this error:
Objects are in the array and show up on the screen, but are not animated.
This is what the HTML code looks like, where I iterate through the table and display the elements that I want to be slowly displayed (animation):
<section [#listAnimation]="articles.length">
<div *ngFor="let article of articles">
<div class="card border-0">
<div class="row no-gutters">
<div class="col-md-4 mt-3">
<div class="container-text-image">
<img [src]="article.mainImageSrc" onerror="this.onerror=null; this.src='..\..\..\assets\notFound.png';" class="card-img" [alt]="article.mainImageFullName">
<div class="label bottom-left">
<h3 class="label-text">
{{article.category}}
</h3>
</div>
</div>
</div>
<div class="col-md-8">
<div class="card-body">
<h5 class="card-title mt-0">{{article.title}}</h5>
<p *ngIf="article.description != null" class="card-text description-text">{{article.description}}</p>
</div>
</div>
</div>
</div>
</div>
</section>
This is what the animation code looks like in a component:
const listAnimation = trigger('listAnimation', [
transition('* <=> *', [
query(':enter',
[style({ opacity: 0 }), stagger('60ms', animate('600ms ease-out', style({ opacity: 1 })))],
),
query(':leave',
animate('200ms', style({ opacity: 0 })),
)
])
]);
#Component({
selector: 'app-articles',
templateUrl: './articles.component.html',
styleUrls: ['./articles.component.css'],
animations: [listAnimation]
})
Here's a snippet of code where I get my backend data into an array:
private fetchArticles = (): void => {
this.loaderService.show();
this.articlesService
.getPortalArticles(this.getArticlesParams())
.pipe(
finalize(() => {
this.setArticleMainImg();
this.loaderService.hide();
})
)
.subscribe(
(result) => {
this.articlesCount = result.totalItemsCount;
this.articles = result.items;
},
(error) => { }
);
}
Any ideas what might be causing the error? I realize that I can add {optional: true} to the animation code, but this will only get rid of the error and the animation will still not work.

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>

TypeError: Cannot read property 'questions' of undefined

Im getting the above error message but dont understand why as everything is defined as far as i can see.
Heres my html:
Apparently, the error occurs on line 1
<div *ngIf="pager.index < quiz.questions.length">
<h5 class="flow-text"><span [innerHTML]="quiz.questions[pager.index].text"></span></h5>
<br>
<div class="row text-left">
<div class="col s12 m12" *ngFor="let answer of quiz.questions[pager.index].answers">
<div class="answer">
<input type="checkbox" [checked]="answer.selected" (change)="onSelect(answer);"/><label class="black-text flow-text"> {{answer.text}} </label>
</div>
</div>
</div>
<footer class="row">
<div class="col s6 m6"></div>
<div class="col s6 m6">
<div *ngIf="pager.index < quiz.questions.length - 1">
<button id="nextButton" class="btn-flat black-text right flow-text" (click)="goTo(pager.index + 1);">Next</button>
</div>
<div *ngIf="pager.index == quiz.questions.length - 1">
<button id="nextButton" class="btn-flat black-text right flow-text" (click)="goTo(pager.index + 1);">Finish</button>
</div>
</div>
</footer>
</div>
<div *ngIf="pager.index == quiz.questions.length">
{{ selections }}
</div>
here is the component.ts
import { Component, OnInit, EventEmitter } from '#angular/core';
import { QuizService } from '../services/quiz.service';
import { Answer, Question, Quiz } from '../models/index';
import {MaterializeAction} from "angular2-materialize";
#Component({
selector: 'app-quiz',
templateUrl: './quiz.component.html',
styleUrls: ['./quiz.component.sass'],
providers: [QuizService]
})
export class QuizComponent implements OnInit {
quiz: Quiz;
pager = {
index: 0,
size: 1,
count: 1
};
selections: [string]
constructor(private quizService: QuizService) { }
ngOnInit() {
this.loadQuiz()
}
loadQuiz() {
this.quizService.get().subscribe(res => {
this.quiz = new Quiz(res);
this.pager.count = this.quiz.questions.length;
});
}
goTo(index: number) {
if (index >= 0 ) {
this.pager.index = index;
}
}
onSelect(answer: Answer) {
if (answer.selected = true) {
this.selections.splice(this.selections.indexOf(answer.text), 1);
} else {
this.selections.push(answer.text);
}
answer.selected = !answer.selected
}
}
i dont understand why its happening as despite the error compiling the code works and runs as it should, apart from the check boxes which i have asked in another question.
You should be using safe navigation operator in this case
*ngIf="pager.index < quiz?.questions?.length"
And
*ngIf="pager.index == quiz?.questions?.length"
It seems quiz variable is undefined, define it like this quiz: Quiz={}