Angular 6:使用FormGroup构建测验并通过分页保存数据

时间:2018-08-22 13:10:18

标签: angular forms typescript pagination formgroups

编辑 this is my full project in stackblitz 课程测验位于“课程测验”文件夹中(课程测验是课程测验的父级)

我正在尝试建立一个独立于页面的测验(每个页面有一个问题)。我正在使用分页进行此操作。 数据从后端传递,并且html和http请求没有问题。 我不需要将答案保存到数据库,因此我想以某种方式使用本地数组。

这是测验的样子:enter image description here

如果我检查答案并移至另一页面并返回该页面,则数据已消失。 我不知道要使用哪种数据结构(也许是int数组?),而且因为仅在最后一页提交按钮,我不知道何时进行更新(设置寻呼机时?)。如何使用formGroup保存数据? 到目前为止,这是我的代码:

组件

import { Component, OnInit, Input } from '@angular/core';
import { ActivatedRoute, Router, Routes, NavigationEnd } from '@angular/router';
import { FormControl, FormBuilder, FormGroup, Validators } from '@angular/forms';

import { ICourse } from '../../course';
import { ISegment } from '../../course';
import { IQuestion } from '../../course';
import { CourseService } from '../../course.service';
import { PagerService } from '../../pager.service';

import * as _ from 'underscore';

@Component({
  selector: 'quiz-course',
  templateUrl: './course-quiz.component.html',
  styleUrls: ['./course-quiz.component.sass']
})

export class CourseQuizComponent implements OnInit {

  // the data I get from course-play component
  @Input() items: IQuestion[];

  // variables for pagination
  pagedItems: IQuestion[];
  pager: any = {};

  answersArray: any[];              // array of answers the user choose
  index: int;                      // current index of answersArray
  sum: int;                       // number of answers the user answered
  public quizForm: FormGroup     // radio buttons in the quiz form

  constructor(private courseService: CourseService,
      private route: ActivatedRoute,
      private router: Router,
      private fb: FormBuilder,
      private pagerService: PagerService) {  }

  ngOnInit() {
    this.setPage(1);
    this.index = 0;
    this.sum = 0;
    this.checked = false;

    this.quizForm = this.fb.group({
      selected: [{value: ''}, [Validators.required]]
    });
  }

  // change pages
  setPage(page: number) {
    if (page < 1 || page > this.pager.totalPages) {
        return;
    }

    // get pager object from service
    this.pager = this.pagerService.getPager(this.items.length, page);

    // get current page of items
    this.pagedItems = this.items.slice(this.pager.startIndex, this.pager.endIndex + 1);

    // do something here to update answersArray
  }

  // getter for easy access to form fields
  get f() {
    return this.quizForm.controls;
  }

  // insert to local array the answers of the user after he press submit
  onSubmit() {

  // if we answered all answers, go to finish page
  if (this.sum == this.items.length) { }


  }

}

html

<!-- If the user didn't answer all the questions -->
  <div class="container" *ngIf="sum < pager.totalPages">
      <div class="text-left quiz-body" *ngFor="let item of pagedItems">
        <form [formGroup]="quizForm" (ngSubmit)="onSubmit()">
          <!-- items being paged -->
          <h3>Question {{item.id}}/{{items.length}}</h3>
          <h6>Question {{item.question}}</h6>
          <div class="form-group">
            <mat-radio-group FormControlName="selected" class="form-control">
              <ul class="items">
                <li><mat-radio-button color="primary" id="answer1" value="1"></mat-radio-button><label for="answer1">1. {{item.answer1}}</label></li>
                <li><mat-radio-button color="primary" id="answer2" value="2"></mat-radio-button><label for="answer2">2. {{item.answer2}}</label></li>
                <li><mat-radio-button color="primary" id="answer3" value="3"></mat-radio-button><label for="answer3">3. {{item.answer3}}</label></li>
                <li><mat-radio-button color="primary" id="answer4" value="4"></mat-radio-button><label for="answer4">4. {{item.answer4}}</label></li>
              </ul>
            </mat-radio-group>
          </div>

          <!-- Submit Buttom will show only on the last page -->
          <div *ngIf="pager.currentPage == pager.totalPages">
            <button type="submit" class="btn btn-primary mb-2">Submit</button>
          </div>


          <!-- pager -->
          <ul *ngIf="pager.pages && pager.pages.length" class="pagination">
              <li class="page-item" [ngClass]="{disabled:pager.currentPage === 1}">
                  <a class="page-link" (click)="setPage(1)">First</a>
              </li>
              <li class="page-item" [ngClass]="{disabled:pager.currentPage === 1}">
                  <a class="page-link" (click)="setPage(pager.currentPage - 1)">Previous</a>
              </li>
              <li class="page-item" *ngFor="let page of pager.pages" [ngClass]="{active:pager.currentPage === page}">
                  <a class="page-link" (click)="setPage(page)">{{page}}</a>
              </li>
              <li class="page-item" [ngClass]="{disabled:pager.currentPage === pager.totalPages}">
                  <a class="page-link" (click)="setPage(pager.currentPage + 1)">Next</a>
              </li>
              <li class="page-item" [ngClass]="{disabled:pager.currentPage === pager.totalPages}">
                  <a class="page-link" (click)="setPage(pager.totalPages)">Last</a>
              </li>
          </ul>
        </form>
      </div>
</div>


<!-- If the user finished the quiz, this div will displaying instead -->
<div class="container" *ngIf="sum == pager.totalPages">
  <h3> You have just finished the quiz! </h3>
</div>

编辑:

这是分页服务:

import * as _ from 'underscore';

export class PagerService {
    getPager(totalItems: number, currentPage: number = 1, pageSize: number = 1) {
        // calculate total pages
        let totalPages = Math.ceil(totalItems / pageSize);

        let startPage: number, endPage: number;
        // if (totalPages <= 10) {
        //     // less than 10 total pages so show all
        //     startPage = 1;
        //     endPage = totalPages;
        // } else {
        //     // more than 10 total pages so calculate start and end pages
        //     if (currentPage <= 6) {
        //         startPage = 1;
        //         endPage = 10;
        //     } else if (currentPage + 4 >= totalPages) {
        //         startPage = totalPages - 9;
        //         endPage = totalPages;
        //     } else {
        //         startPage = currentPage - 5;
        //         endPage = currentPage + 4;
        //     }
        // }

        if (totalPages <= 5) {
            startPage = 1;
            endPage = totalPages;
        } else {
            if (currentPage <= 3) {
                startPage = 1;
                endPage = 5;
            } else if (currentPage + 1 >= totalPages) {
                startPage = totalPages - 4;
                endPage = totalPages;
            } else {
                startPage = currentPage - 2;
                endPage = currentPage+2;
            }
        }

        // calculate start and end item indexes
        let startIndex = (currentPage - 1) * pageSize;
        let endIndex = Math.min(startIndex + pageSize - 1, totalItems - 1);

        // create an array of pages to ng-repeat in the pager control
        let pages = _.range(startPage, endPage + 1);

        // return object with all pager properties required by the view
        return {
            totalItems: totalItems,
            currentPage: currentPage,
            pageSize: pageSize,
            totalPages: totalPages,
            startPage: startPage,
            endPage: endPage,
            startIndex: startIndex,
            endIndex: endIndex,
            pages: pages
        };
    }
}

2 个答案:

答案 0 :(得分:0)

如果我是你,我会转而路由整个问题模块并使用sharign服务来处理该问题。

我快速stackblitz向您展示了一个示例。

当然可以改进,但这只是为了让您对我的想法有所了解。

我认为您的情况是路由的完美示例。不仅如此,使用这种方法,您的代码将变得更具可读性,可重用性和清晰性。

答案 1 :(得分:-1)

  1. 如果您可以通过索引识别问题,则可以使用数组。另一个问题是,当用户应为单个问题选择多个答案(不是单选,而是复选框)时,它可能不是整数数组而是对象数组。
  2. 您不仅要处理提交的内容,还要导航到其他页面,并在用户导航到其他页面时将选择的答案存储在数组中

编辑

您可以通过订阅无线电组变更值事件来实现所选答案的保存:

this.formGroup.controls['selected'].valueChanges.subscribe(value => {
    // TODO: save selected abswer in the array
});