Angular 6测验形式:在页面之间绑定和保存数据

时间:2018-08-21 12:52:54

标签: html angular forms typescript

我的项目包含4个组件:“课程列表”,“课程详细信息”,“课程播放”,“课程测验”,方案如下:enter image description here 数据是这样传递的:每个课程都有部分数组,每个部分都有问题数组。我从后端服务器(Ruby on Rails API项目)获得的所有数据均正确传递。

这是每个数据结构的接口:

export interface ICourse {
  id: number;
  title: string;
  autor: string;
  segments: ISegment[];
}

export interface ISegment {
  id: number;
  unit_id: number;
  unit_title: string;
  name: string;
  type: string;
  data: string;
  questions: IQuestion[];
}

export interface IQuestion {
  id: number;
  question: string;
  answer1: string;
  answer2: string;
  answer3: string;
  answer4: string;
  correct: number;
}

我的课程测验组件有问题。 这是测验的外观: enter image description here

问题:

  1. 点击提交后,接下来的数据将不保存
  2. 我要添加按提交后为正确答案和用户答案着色的选项
  3. 我希望当所有问题都得到回答后,改为显示新页面(可能因为第一个不起作用)

This is the project in stackblitz。该项目无法正常工作,因为stackblitz无法与sass一起工作。我还将在此处添加相关代码:

app-routing.module.ts

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { CourseListComponent } from './courses/course-list/course-list.component';
import { CourseDetailComponent } from './courses/course-detail/course-detail.component';
import { CoursePlayComponent } from './courses/course-play/course-play.component';
import { PageNotFoundComponent } from './page-not-found/page-not-found.component';
import { CourseQuizComponent } from './courses/course-play/course-quiz/course-quiz.component';


// Routing array - set routes to each html page
const appRoutes: Routes = [
  { path: '', redirectTo: '/courses', pathMatch: 'full', runGuardsAndResolvers: 'always' },
  { path: 'courses', component: CourseListComponent,  pathMatch: 'full', runGuardsAndResolvers: 'always' },
  { path: 'courses/:id', component: CourseDetailComponent, pathMatch: 'full', runGuardsAndResolvers: 'always' },
  { path: 'courses/:id/segments/:id', component: CoursePlayComponent, pathMatch: 'full', runGuardsAndResolvers: 'always',
    children: [{ path: 'questions/:id', component: CourseQuizComponent }]
  },
  { path: '**', component: PageNotFoundComponent, pathMatch: 'full', runGuardsAndResolvers: 'always' }];

@NgModule({
  imports: [RouterModule.forRoot(appRoutes, { onSameUrlNavigation: 'reload' })],
  exports: [RouterModule]
})

export class AppRoutingModule {  }

course-play.component.ts

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router, Routes, NavigationEnd } from '@angular/router';
import { MatSidenavModule } from '@angular/material/sidenav';
import { LocalStorage } from '@ngx-pwa/local-storage';
import { DomSanitizer } from '@angular/platform-browser';

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


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

export class CoursePlayComponent implements OnInit {
  errorMessage: string;
  course: ICourse;
  courseId: number;
  public currentSegment: ISegment;
  public showChildren: boolean = false;

  constructor(private courseService: CourseService,
      private route: ActivatedRoute,
      private router: Router,
      public sanitizer: DomSanitizer) { }


    ngOnInit() {
        // save this course id from course-detail and get http request from the service
        this.courseId = JSON.parse(localStorage.getItem("courseId"))
        this.getCourse(this.courseId);
      }

      // Get course detail by id
      getCourse(id: number) {
        this.courseService.getCourse(this.courseId).subscribe(
          course => {
              this.course = course;

              // get the current segment id to use it on the html file
              const id = +this.route.snapshot.paramMap.get('id');
              this.getCurrentSegment(id);
          },
          error  => this.errorMessage = <any>error);
        }

      // search in course single segment by id and save it in currentSegment
      // to use it in the html file
      getCurrentSegment(id: number){
          this.currentSegment = this.course.segments.find(d => d.id === id);
      }

      changeShowChildren() {
        this.showChildren = !this.showChildren;
      }
}

course-play.component.html

  <div class="row content" *ngIf="course">
    <!-- Side nav-bar -->
    <div class="col-md-3">
      <!-- Image Logo -->
      <div id="head_sidebar">
        <img src="./assets/images/lg-white.png" class="d-inline-block align-top logo" alt="" routerLink="/courses" style="outline: none">
        <h3>{{course.title}}</h3>
      </div>

      <div class="col-md-12 sidenav">
        <!-- Menu elemets -->
        <div class="nav nav-pills nav-stacked" *ngFor="let unit of course.segments | groupBy: 'unit_title'; let i = index">
          <h6 class="course_play_title">Unit {{ i+1 }}: {{ unit.key }} </h6>
          <ul>
            <li class="course_play_item"  *ngFor="let lesson of unit.value">
              <a class="nav-link" [routerLink]="['/courses', course.id, 'segments', lesson.id]" (click)=getCurrentSegment(lesson.id)>{{lesson.name}}</a>
            </li>
          </ul>
        </div>
      </div>
    </div>

    <!-- Body -->
    <div class="col-md-9 no-gutters" *ngIf="currentSegment">
      <!-- Video Div -->
      <div class="col-md-12 course_play_body text-center" *ngIf="currentSegment.segment_type === 'Video'">
        <h1>{{currentSegment.name}}</h1>
        <p class="small-text" *ngIf="course.segments?.length > 0">lesson {{currentSegment.id}} of {{course.segments?.length}}</p>
        <hr>
        <iframe frameborder="0" allowfullscreen="true" [src]='currentSegment.data | safe'></iframe>
        <button type="button" class="prev btn btn-primary btn-lg" *ngIf="currentSegment.id > 1" [routerLink]="['/courses', course.id, 'segments', currentSegment.id-1]" (click)=getCurrentSegment(currentSegment.id-1)>Previous</button>
        <button type="button" class="next btn btn-primary btn-lg" *ngIf="currentSegment.id < course.segments?.length" [routerLink]="['/courses', course.id, 'segments', currentSegment.id+1]" (click)=getCurrentSegment(currentSegment.id+1)>Next</button>
      </div>

      <!-- Quiz Div -->
      <div class="col-md-12 course_play_body" *ngIf="currentSegment.segment_type === 'Quiz'">
        <div class="col-md-12 course_play_body text-center" *ngIf="showChildren === false">
          <h1>{{currentSegment.name}}</h1>
          <p class="text-left"> Now that you've finished this unit, It's time to take a short quiz and see what you learned so far!
              You'll need to choose one out of four answers which you think is correct.
              After you've finished the quiz, you'll get your grade. feel free to re-take this quiz as much as you like.
              Good Luck!
            </p>
            <p class="text-left big-text"> {{currentSegment.questions.length}} questions </p>
            <a (click) = "showChildren = true"><h4>Start Quiz</h4></a>

            <button style="margin-top: 30%" type="button" class="prev btn btn-primary btn-lg" *ngIf="currentSegment.id > 1" [routerLink]="['/courses', course.id, 'segments', currentSegment.id-1]" (click)=getCurrentSegment(currentSegment.id-1)>Previous</button>
            <button style="margin-top: 30%" type="button" class="next btn btn-primary btn-lg" *ngIf="currentSegment.id < course.segments?.length" [routerLink]="['/courses', course.id, 'segments', currentSegment.id+1]" (click)=getCurrentSegment(currentSegment.id+1)>Next</button>
          </div>
            <quiz-course *ngIf="showChildren === true" [items]="currentSegment?.questions"></quiz-course>
        </div>

  </div>

course-quiz.component.ts

import { Component, OnInit, Input } from '@angular/core';
import { ActivatedRoute, Router, Routes, NavigationEnd } from '@angular/router';

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 = {};

  public userAnswers = ['0', '0', '0', '0'];    // array of user answers
  public index: int;                            // index of userAnswers
  public checkedAnswer: int;                    // the checked answer the user choose
  public correctAnswer: boolean = false;        // true if his answer correct, else false
  public sum: int;                              // sum of the questions answered. needed to check if user finished quiz

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

  ngOnInit() {
    this.setPage(1);
    this.checkedAnswer = 0;
    this.index = 0;
    this.sum = 0;
  }

  // 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);
  }

  isChecked(value){
    this.checkedAnswer = value;
  }

  // get value of the checked answer, check if it's correct and save it to the answer array
  submitAnswer(correct) {

    // if the user answer all the questions, go to finished page
    if (sum == this.items.length) {
    
    }

    if (this.checkedAnswer == 0) {
      // do something to notify user that an answer need to be checked
    }

    else if (this.checkedAnswer == correct) {
      this.correctAnswer = true;
      this.userAnswers[this.index] = "correct";
    }

    else {
      this.correctAnswer = false;
      this.userAnswers[this.index] = "incorrect";
    }

    this.index = this.index + 1;
    this.sum = this.sum + 1;
  }

}

course-quiz.component.html

  <div class="container" *ngIf="sum < 4">
      <div class="text-left quiz-body" *ngFor="let item of pagedItems">
        <form>
          <!-- items being paged -->
          <h3>Question {{item.id}}/{{items.length}}</h3>
          <h6>Question {{item.question}}</h6>
          <ul class="items">
            <li><input type="radio" id="answer1" name="answer" value="1" (click)="isChecked(1)"><label for="answer1">1. {{item.answer1}}</label></li>
            <li><input type="radio" id="answer1" name="answer" value="2" (click)="isChecked(2)"><label for="answer2">2. {{item.answer2}}</label></li>
            <li><input type="radio" id="answer1" name="answer" value="3" (click)="isChecked(3)"><label for="answer3">3. {{item.answer3}}</label></li>
            <li><input type="radio" id="answer1" name="answer" value="4" (click)="isChecked(4)"><label for="answer4">4. {{item.answer4}}</label></li>
          </ul>

          <button type="submit" class="btn btn-primary mb-2" (click)="submitAnswer(item.correct)">Submit</button>
          <!-- Submit Buttom -->


          <!-- 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 == 4">
  <h3> You have just finished the quiz! </h3>
</div>

0 个答案:

没有答案