如何对动态嵌套数组字段的值求和并为每个输入字段创建一个对象

问题描述 投票:0回答:1

我正在尝试为使用Angular 8的课程开发数字评分系统。实际情况非常复杂,因此我分开了一部分,并创建了一个新项目来解释问题所在。如果您查看图像,您将了解我正在尝试实现的目标。假设这是一门课程的年级形式。对于一门课程,可以有不同的考试。报名参加此课程的学生,他们将参加该课程的那些特定考试,然后老师将使用此表格提交编号。假设对于第一行第一列(中考),该表格不应允许您提供超过25个标记或小于零的标记。如果您在期中考试字段中输入20,则Total将显示20,GP将显示0.00,成绩将显示F。然后,如果您在期末考试字段中输入30,则总值将更新为50,GP将更新。到0.00,并将更新为F。如果再次在“评估”字段上输入40,则“总值”将更新为90,“ GP”将更新为4.00,并将更新为A。所有行都将发生相同的情况。如果单击“保存”按钮,将提交数字。

enter image description here

[现在,我正在描述我尝试过的代码和问题,这里studentListexamListgradePointList数组将填充来自后端服务的课程数据。我创建了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是动态的,所以也会从列表中生成数组。

我假设我在表单上创建时遇到问题,或者我的方法是错误的。请帮助我完成目标,生成总分并创建成绩列表。将不胜感激。预先感谢。

angular typescript angular-reactive-forms angular-forms
1个回答
0
投票

好吧,为了满足您的要求,您必须使用嵌套数组,您需要遵循此结构,或者至少遵循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)); }

working stackblitz here

© www.soinside.com 2019 - 2024. All rights reserved.