I am creating a dynamic table. The problem with my json structure below is that the Students object does not contain Subjects array within the object, but rather Students[] and Subjects[] are defined through Links[], where there is link defined for student a subject.
The output of the table should look like this:
Do you have any suggestions how to create *ngFor in ??? area that links each student to its subjects?
The json structure looks like this:
export class StudentsAndSubjects {
info: SchoolInformation;
}
export class SchoolInformation {
students: Students[];
subjects: Subjects[];
links: Links[];
}
export class Students {
id: string; //example: student_1
name: string;
surname: string;
};
export class Subjects{
id: string; //example: subject_1
name: string;
};
export class Links{
studentId: string; //example: student_1
subjectId: string; //example: subject_1
};
The table structure:
@Component({
selector: 'app-student-and-subjects',
template: `
<table>
<tr *ngFor="let row of rowHeaders">
<td *ngFor="let item of data.info.students.name">
<span *ngIf="row !== 'Subjects'">{{ item[row] }}</span>
</td>
<table *ngIf="row === 'Subjects'">
<tr **???**>
<td>{{ subject}}</td>
</tr>
</table>
</tr>
</table>
`;
})
export class StudentsAndSubjects {
@Input() data: StudentSubjectData;
readonly rowHeaders = ['Student','Subjects']
}
First, I think you need to restructure your table a bit. Since the table of subjects is associated to a particular student, it should probably live inside the td
that contains that student's data:
<table>
<tr *ngFor="let row of rowHeaders">
<td *ngFor="let student of data.info.students"> <--- each td contains data for a student
<span *ngIf="row !== 'Subjects'">{{ student.name }}</span>
<table *ngIf="row === 'Subjects'"> <--- move this table inside the td
<tr>
<td *ngFor="let subject of getSubjectsForStudent(student)"> <-- the *ngFor you were missing
{{ subject.name }}
</td>
</tr>
</table>
</td>
</tr>
</table>
Also note that I changed your *ngFor="let item of data.info.students.name"
so it iterates over data.info.students
rather than data.info.students.name
since you need the student instance data (and data.info.students.name
isn't a collection).
And to display the student name, I replaced {{ item[row] }}
with {{ student.name }}
.
Then, to display the subjects for that student, you would need to create a method that accepts the student object (or just its id
) and then parses the data and returns the student's associated subjects.
That method is what you would need in the missing *ngFor
that you're asking about.
(Alternatively, of course, you could transform the data ahead of time into a mapping object that maps the students to their subjects.)
So the missing *ngFor
that you're asking about would look something like this:
<td *ngFor="let subject of getSubjectsForStudent(student)">
Note that it's on the td
, not the tr
like in your markup. That's because each subject has its own cell, not its own row—all subjects are in the same row.
Here's a StackBlitz showing this approach.