我正在尝试为使用Angular 8的课程开发数字评分系统。实际情况非常复杂,因此我分开了一部分,并创建了一个新项目来解释问题所在。如果您查看图像,您将了解我正在尝试实现的目标。假设这是一门课程的年级形式。对于一门课程,可以有不同的考试。报名参加此课程的学生,他们将参加该课程的那些特定考试,然后老师将使用此表格提交编号。假设对于第一行第一列(中考),该表格不应允许您提供超过25个标记或小于零的标记。如果您在期中考试字段中输入20,则Total
将显示20,GP将显示0.00,成绩将显示F。然后,如果您在期末考试字段中输入30,则总值将更新为50,GP将更新。到0.00,并将更新为F。如果再次在“评估”字段上输入40,则“总值”将更新为90,“ GP”将更新为4.00,并将更新为A。所有行都将发生相同的情况。如果单击“保存”按钮,将提交数字。
[现在,我正在描述我尝试过的代码和问题,这里studentList
,examList
和gradePointList
数组将填充来自后端服务的课程数据。我创建了populateSomeDemoData
方法来生成此数据。 studentList是Student对象的数组,其中包含学生的ID和姓名。 examList是Exam对象的数组,其中包含考试ID,考试名称和该考试的总分。 gradePointList包含字母等级和等级点数的范围。假设如果总分数在90(最小数字)和100(最大数字)之间,则分数将为4.00,字母分数将为A。领域。但是为此,我无法使用表单控件访问特定的字段,这就是为什么我无法计算一行的总分数和分数。同样出于相同的原因,我无法创建将发送到后端的成绩对象列表。 gradeForm
是每个字段的对象,其中将包含学生,考试和号码。如果字段被更新,则该成绩对象也将被更新。如果触发“保存”按钮,则此数字列表将传递到后端。
HTML部分是:
Grade
TypeScript部分为:
<form [formGroup]="gradeForm" (ngSubmit)="saveGrade()">
<table>
<thead>
<tr>
<th> #</th>
<th>Student</th>
<th *ngFor="let exam of examList">{{exam.name}} ({{exam.marks}}%)</th>
<th>Total</th>
<th>GP</th>
<th>Grade</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let student of studentList; let i = index">
<th> {{ i + 1 }} </th>
<th> {{ student.id }} <br/> {{student.name}} </th>
<th *ngFor="let grade of gradeFields.controls; let j = index" formArrayName="gradeFields">
<input type="number" [formControlName]="j">
</th>
<th>??</th>
<th>??</th>
<th>??</th>
</tr>
</tbody>
</table>
<div class="wrapper">
<button class="button">Save Grade</button>
</div>
</form>
我创建了一个StackBlitz,以更好地理解代码。请单击此链接查看代码。 export class AppComponent {
public gradeForm: FormGroup;
// This arrays will populate dynamically from the database
public examList: Exam[] = [];
public studentList: Student[] = [];
public gradePointList: GradePoint[] = [];
public gradeList: Grade[] = [];
constructor(private formBuilder: FormBuilder) {
this.populateSomeDemoData();
this.createGradeForm();
}
createGradeForm(): void {
this.gradeForm = this.formBuilder.group({
gradeFields: this.formBuilder.array([
this.formBuilder.control('')
])
});
for (let i = 0; i < this.examList.length - 1; i++) {
this.gradeFields.push(this.formBuilder.control(''));
}
}
get gradeFields() {
return this.gradeForm.get('gradeFields') as FormArray;
}
saveGrade(): void {
console.log(this.gradeForm.get('gradeFields').value);
console.log(this.gradeList);
console.log('Grade List Saved');
}
populateSomeDemoData(): void {
// Static value for populating arrays for easy explanation
const midTerm = new Exam();
midTerm.id = '1';
midTerm.name = 'Mid Exam';
midTerm.marks = 25;
const finalExam = new Exam();
finalExam.id = '2';
finalExam.name = 'Final Exam';
finalExam.marks = 30;
const assessmentExam = new Exam();
assessmentExam.id = '3';
assessmentExam.name = 'Assessment';
assessmentExam.marks = 40;
const attendance = new Exam();
attendance.id = '4';
attendance.name = 'Attendance';
attendance.marks = 5;
this.examList.push(midTerm);
this.examList.push(finalExam);
this.examList.push(assessmentExam);
this.examList.push(attendance);
// Static value for populating arrays for easy explanation
const student1 = new Student();
student1.id = '14101561';
student1.name = 'Petey Cruiser';
const student2 = new Student();
student2.id = '14112201';
student2.name = 'Bob Frapples';
const student3 = new Student();
student3.id = '14112202';
student3.name = 'Paul Molive';
const student4 = new Student();
student4.id = '16113004';
student4.name = 'Anna Mull';
const student5 = new Student();
student5.id = '16113005';
student5.name = 'Gail Forcewind';
this.studentList.push(student1);
this.studentList.push(student2);
this.studentList.push(student3);
this.studentList.push(student4);
this.studentList.push(student5);
// Static value for populating arrays for easy explanation
const aGradePoint = new GradePoint();
aGradePoint.minimumNumber = 90;
aGradePoint.maximumNumber = 100;
aGradePoint.gradePoint = 4;
aGradePoint.letterGrade = 'A';
const bGradePoint = new GradePoint();
bGradePoint.minimumNumber = 80;
bGradePoint.maximumNumber = 89;
bGradePoint.gradePoint = 3.5;
bGradePoint.letterGrade = 'B';
const cGradePoint = new GradePoint();
cGradePoint.minimumNumber = 70;
cGradePoint.maximumNumber = 79;
cGradePoint.gradePoint = 3;
cGradePoint.letterGrade = 'C';
const dGradePoint = new GradePoint();
dGradePoint.minimumNumber = 60;
dGradePoint.maximumNumber = 69;
dGradePoint.gradePoint = 2.5;
dGradePoint.letterGrade = 'D';
const fGradePoint = new GradePoint();
fGradePoint.minimumNumber = 0;
fGradePoint.maximumNumber = 59;
fGradePoint.gradePoint = 0;
fGradePoint.letterGrade = 'F';
this.gradePointList.push(aGradePoint);
this.gradePointList.push(bGradePoint);
this.gradePointList.push(cGradePoint);
this.gradePointList.push(dGradePoint);
this.gradePointList.push(fGradePoint);
}
}
export class Student {
public id: string;
public name: string;
constructor(student?) {
student = student || {};
this.id = student.id || null;
this.name = student.name || null;
}
}
export class Exam {
public id: string;
public name: string;
public marks: number;
constructor(exam?) {
exam = exam || {};
this.id = exam.id || null;
this.name = exam.name || null;
this.marks = exam.marks || 0;
}
}
export class GradePoint {
public minimumNumber: number;
public maximumNumber: number;
public gradePoint: number;
public letterGrade: string;
constructor(gradePoint?) {
gradePoint = gradePoint || {};
this.minimumNumber = gradePoint.minimumNumber || 0;
this.maximumNumber = gradePoint.maximumNumber || 59;
this.gradePoint = gradePoint.gradePoint || 0;
this.letterGrade = gradePoint.letterGrade || 'F';
}
}
export class Grade {
public student: Student;
public exam: Exam;
public number: number;
constructor(grade?) {
grade = grade || {};
this.student = grade.student || null;
this.exam = grade.exam || null;
this.number = grade.number || null;
}
}
我看到了很多与表单数组有关的帖子,但是我的情况却大不相同。在这里,我没有任何添加按钮来推送数组或计算值。并且所有情况都有固定的形式。但是在我的情况下,因为examList是动态的,所以也会从列表中生成数组。
我假设我在表单上创建时遇到问题,或者我的方法是错误的。请帮助我完成目标,生成总分并创建成绩列表。将不胜感激。预先感谢。
好吧,为了满足您的要求,您必须使用嵌套数组,您需要遵循此结构,或者至少遵循2 d数组,grades [] []:grades [studentId] [examId],当您阅读代码时,您将了解更多,代码中缺少很多内容,例如标记的验证以及总计和GP字段的计算,我不会打扰这些部分(我添加了一个用于计算和验证的示例,但是您需要对其进行修改),但是我将向您展示如何正确填充表单组以及如何使用它,并具有动态视图。正如我提到的那样,您需要一个2D数组,对我来说,我可以获得更多信息,所以我有一个对象数组,该对象具有2个属性,一个是学生控件(持有学生ID),一个是为此成绩的数组学生这是我用来填充表单组的循环
Click here
对于您的视图,您将嵌套ng-for,一个用于循环显示学生行,另一个用于循环显示您的成绩(列)
createGradeForm(): void {
this.gradeForm = this.formBuilder.group({
gradeFields: this.formBuilder.array([])
});
//loop all students
for (let b = 0; b < this.studentList.length; b++) {
// create a form group to hold student data
const userGroup = this.formBuilder.group({
student: this.formBuilder.control(this.studentList[b].id),
grades: this.formBuilder.array([])
})
//populate grades form array
for (let i = 0; i < this.examList.length; i++) {
//Bonus, I added a validator for you, max value is the mark, please apply min and other validations on your own.
userGroup.get('grades').push(this.formBuilder.control('', [Validators.max(this.examList[i].marks)]));
}
// add the form group to your array
this.gradeFields.push(userGroup);
}
//Check result here
console.log(this.gradeFields);
}
获取总功能
<tbody>
<!-- loop through the higher level array (students) -->
<ng-container *ngFor="let student of gradeFields.controls; let i = index" formArrayName='gradeFields'>
<ng-container [formGroupName]='i'>
<tr>
<th> {{ i + 1 }} </th>
<-- this is student control -->
<th> {{ student.get('student').value }} </th>
<-- loop through your grades array -->
<th *ngFor="let grade of student.get('grades').controls; let j = index" formArrayName="grades">
<-- bonus here, I added an example for validation, add style to your css for .inValid to see when invalid -->
<input [class.inValid]='!grade.valid' type="number" [formControlName]="j">
</th>
<-- one more bonus, an example of calculation getTotal -->
<th>{{getTotal(i)}}</th>
<th>??</th>
<th>??</th>
</tr>
</ng-container>
</ng-container>
</tbody>
//It takes the index of the student, get all grades, and accumlate them, the logic is wrong, please modify it, I just sum all grades, you have to add the logic
getTotal(ind) {
const studentGrades = this.gradeFields.value[ind].grades;
return studentGrades.reduce((a, b) => Number(a) + Number(b));
}