im trying to render a component that is inside a ng-for, but the content of the component will be trigger after a click on a button, the content will be captured and then sent to the child component. After that i need to render the child component using the data that i have obtained by the click. But the child component need to be render inside the same index in ng-for and not to render in all indexes of the array.
Here we can see some code:
Parent component HTML
<div >
<div >
<div *ngFor="let pessoa of lista; index as i" >
<div >
<div >
<span > Diretor </span>
<span > {{pessoa.nome}}</span>
</div>
</div>
<div *ngFor="let x of pessoa.filmes">
<mat-card >
<mat-card-header>
<mat-card-subtitle>{{x.tipo}}</mat-card-subtitle>
<mat-card-title>{{ x.nome}}</mat-card-title>
</mat-card-header>
<img mat-card-image src="{{x.imgPath}}" alt="{{x.imgDesc}}">
<mat-divider></mat-divider>
<mat-card-actions>
<button mat-button color="primary" (click)="openDetails(pessoa.id, x);" >Detalhes</button>
</mat-card-actions>
</mat-card>
</div>
<ng-container *ngIf="click">
<app-teste2 [objFilme]="heranca"></app-teste2>
</ng-container>
</div>
</div>
</div>
Parent component TS
import { Component } from '@angular/core';
@Component({
selector: 'app-teste1',
templateUrl: './teste1.component.html',
styleUrls: ['./teste1.component.scss']
})
export class Teste1Component {
lista = [
{nome:'Beltrano', id:1,
filmes:[
{ imgDesc:'community',imgPath:'../../../assets/community.jpg', nome:'Community', tipo:'Serie', duracao:'3:20'},
{ imgDesc:'Avatar',imgPath:'../../../assets/avatar1.jpg', nome:'Avatar', tipo:'Filme', duracao:'3:20'},
{ imgDesc:'Jujutsu no Kaisen',imgPath:'../../../assets/jjk.jpg', nome:'Jujutsu no Kaizen', tipo:'Anime', duracao:'3:20'},
{ imgDesc:'Kamen Rider',imgPath:'../../../assets/kmrider.jpg', nome:'Kamem-rider', tipo:'Dorama', duracao:'3:20'}]},
{nome:'Fulano', id:2,
filmes:[
{ imgDesc:'community',imgPath:'../../../assets/community.jpg' ,nome:'Community', tipo:'Serie', duracao:'3:20'},
{ imgDesc:'Avatar',imgPath:'../../../assets/avatar1.jpg' ,nome:'Avatar', tipo:'Filme', duracao:'3:20'},
{ imgDesc:'Jujustu no Kaisen',imgPath:'../../../assets/jjk.jpg' ,nome:'Jujutsu no Kaizen', tipo:'Anime', duracao:'3:20'},
{ imgDesc:'Kamen Rider',imgPath:'../../../assets/kmrider.jpg' ,nome:'Kamem-rider', tipo:'Dorama', duracao:'3:20'}]},
{nome:'Ciclano', id:3,
filmes:[
{ imgDesc:'community',imgPath:'../../../assets/community.jpg' ,nome:'Community', tipo:'Serie', duracao:'3:20'},
{ imgDesc:'Avatar',imgPath:'../../../assets/avatar1.jpg' ,nome:'Avatar', tipo:'Filme', duracao:'3:20'},
{ imgDesc:'Jujutsu no Kaisen',imgPath:'../../../assets/jjk.jpg' ,nome:'Jujutsu no Kaizen', tipo:'Anime', duracao:'3:20'},
{ imgDesc:'Kamen Rider',imgPath:'../../../assets/kmrider.jpg' ,nome:'Kamem-rider', tipo:'Dorama', duracao:'3:20'}]},
{nome:'Giclano', id:4,
filmes:[
{ imgDesc:'community',imgPath:'../../../assets/community.jpg' ,nome:'Community', tipo:'Serie', duracao:'3:20'},
{ imgDesc:'Avatar',imgPath:'../../../assets/avatar1.jpg' ,nome:'Avatar', tipo:'Filme', duracao:'3:20'},
{ imgDesc:'Jujutsu no Kaisen',imgPath:'../../../assets/jjk.jpg' ,nome:'Jujutsu no Kaizen', tipo:'Anime', duracao:'3:20'},
{ imgDesc:'Kamen Rider',imgPath:'../../../assets/kmrider.jpg' ,nome:'Kamem-rider', tipo:'Dorama', duracao:'3:20'}]},
]
heranca: any
click!: boolean
array: any[] = []
openDetails(id:number, filme:any){
this.click = true
this.heranca = {
id_diretor:id,
nome: filme.nome,
tipo: filme.tipo,
duracao: filme.duracao,
descricao: "Filme ou série xpto"
}
this.saveIntoArray(this.heranca)
}
saveIntoArray(filme: any){
this.array.push(filme)
console.log(this.array)
}
}
Child Component HTML
<mat-card>
<mat-card-content>
<div >
<span >Filme:
<span >{{filme.nome}}</span>
</span>
<span >Duração:
<span >{{filme.duracao}}</span>
</span>
<span >Descrição:
<span >{{filme.descricao}}</span>
</span>
</div>
</mat-card-content>
</mat-card>
Child component TS
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
@Component({
selector: 'app-teste2',
templateUrl: './teste2.component.html',
styleUrls: ['./teste2.component.scss']
})
export class Teste2Component implements OnChanges{
@Input() objFilme:any
filme: any;
ngOnChanges(changes: SimpleChanges){
for (const propname in changes){
const chg = changes[propname]
const cur = chg.currentValue
console.log(cur);
if (cur) {
this.filme = cur
}
}
}
}
What i achived
When i click on button "detalhes" open a card on the right with the data of the selected card but it duplicate for all others lines too.
What i want to achive When i click on the button "detalhes" i need to open a card on the right with the selected data just for that line.
Im already try to create a ng-for inside the container to match the main ng-for index to render just for the correct container.
CodePudding user response:
Why not creating a new, additional component that represents a row in your 'card-table'? If this new CardRowComponent contained the heranca: any
-property, it would mean that every card-row can display ones own herana
-value.
In my solution there would be 3 components (and possibly 1 service):
- Teste1Component (modified)
- CardRowComponent (new)
- Teste2Component (unchanged)
- Optional: A Service that contains
array: any[] = [];
The CardRowComponent HTML could look like this:
<div *ngFor="let x of filmes">
<mat-card >
<mat-card-header>
<mat-card-subtitle>{{x.tipo}}</mat-card-subtitle>
<mat-card-title>{{ x.nome}}</mat-card-title>
</mat-card-header>
<img mat-card-image src="{{x.imgPath}}" alt="{{x.imgDesc}}">
<mat-divider></mat-divider>
<mat-card-actions>
<button mat-button color="primary" (click)="openDetails(pessoa.id, x);" >Detalhes</button>
</mat-card-actions>
</mat-card>
</div>
<ng-container *ngIf="click">
<app-teste2 [objFilme]="heranca"></app-teste2>
</ng-container>
The CardRowComponent TS would look something like this:
import { Component } from '@angular/core';
@Component({
selector: 'app-card-row',
templateUrl: './card-row.component.html',
styleUrls: ['./card-row.component.scss']
})
export class CardRowComponent {
@Input()
filmes!: any[];
heranca: any;
click!: boolean;
array: any[] = [];
openDetails(id:number, filme:any){
this.click = true
this.heranca = {
id_diretor:id,
nome: filme.nome,
tipo: filme.tipo,
duracao: filme.duracao,
descricao: "Filme ou série xpto"
}
this.saveIntoArray(this.heranca)
}
saveIntoArray(filme: any){
this.array.push(filme)
console.log(this.array)
}
}
The Parent-Component HTML would look something like this:
<div *ngFor="let pessoa of lista; index as i" >
<div >
<div >
<span > Diretor </span>
<span > {{pessoa.nome}}</span>
</div>
</div>
<app-card-row [filmes]="pessoa.filmes"></app-card-row>
</div>
The Parent-Component TS would just contain the movies-list:
import { Component } from '@angular/core';
@Component({
selector: 'app-teste1',
templateUrl: './teste1.component.html',
styleUrls: ['./teste1.component.scss']
})
export class Teste1Component {
lista = [
{nome:'Beltrano', id:1,
filmes:[
{ imgDesc:'community',imgPath:'../../../assets/community.jpg', nome:'Community', tipo:'Serie', duracao:'3:20'},
{ imgDesc:'Avatar',imgPath:'../../../assets/avatar1.jpg', nome:'Avatar', tipo:'Filme', duracao:'3:20'},
{ imgDesc:'Jujutsu no Kaisen',imgPath:'../../../assets/jjk.jpg', nome:'Jujutsu no Kaizen', tipo:'Anime', duracao:'3:20'},
{ imgDesc:'Kamen Rider',imgPath:'../../../assets/kmrider.jpg', nome:'Kamem-rider', tipo:'Dorama', duracao:'3:20'}]},
{nome:'Fulano', id:2,
filmes:[
{ imgDesc:'community',imgPath:'../../../assets/community.jpg' ,nome:'Community', tipo:'Serie', duracao:'3:20'},
{ imgDesc:'Avatar',imgPath:'../../../assets/avatar1.jpg' ,nome:'Avatar', tipo:'Filme', duracao:'3:20'},
{ imgDesc:'Jujustu no Kaisen',imgPath:'../../../assets/jjk.jpg' ,nome:'Jujutsu no Kaizen', tipo:'Anime', duracao:'3:20'},
{ imgDesc:'Kamen Rider',imgPath:'../../../assets/kmrider.jpg' ,nome:'Kamem-rider', tipo:'Dorama', duracao:'3:20'}]},
{nome:'Ciclano', id:3,
filmes:[
{ imgDesc:'community',imgPath:'../../../assets/community.jpg' ,nome:'Community', tipo:'Serie', duracao:'3:20'},
{ imgDesc:'Avatar',imgPath:'../../../assets/avatar1.jpg' ,nome:'Avatar', tipo:'Filme', duracao:'3:20'},
{ imgDesc:'Jujutsu no Kaisen',imgPath:'../../../assets/jjk.jpg' ,nome:'Jujutsu no Kaizen', tipo:'Anime', duracao:'3:20'},
{ imgDesc:'Kamen Rider',imgPath:'../../../assets/kmrider.jpg' ,nome:'Kamem-rider', tipo:'Dorama', duracao:'3:20'}]},
{nome:'Giclano', id:4,
filmes:[
{ imgDesc:'community',imgPath:'../../../assets/community.jpg' ,nome:'Community', tipo:'Serie', duracao:'3:20'},
{ imgDesc:'Avatar',imgPath:'../../../assets/avatar1.jpg' ,nome:'Avatar', tipo:'Filme', duracao:'3:20'},
{ imgDesc:'Jujutsu no Kaisen',imgPath:'../../../assets/jjk.jpg' ,nome:'Jujutsu no Kaizen', tipo:'Anime', duracao:'3:20'},
{ imgDesc:'Kamen Rider',imgPath:'../../../assets/kmrider.jpg' ,nome:'Kamem-rider', tipo:'Dorama', duracao:'3:20'}]},
]
}
The current Teste2Component would remain unchanged.
Hint: Since you possibly want to have a global array: any[] = [];
that is shared among all card-rows, you could move this array to a service and then inject the service into CardRowComponent
via constructor.