角度6:修补程序后视图未显示更新

时间:2018-10-29 12:24:49

标签: angular typescript view httpclient patch

我有一个用户和课程的项目,如果用户看了课或完成了测验,我会更新数据库。修补程序之后,我可以看到数据库正确更新,但是当我在更新后调用get来获取新数据时,数据保持与更新前相同。只有刷新页面后,我才能看到更改。

course-play.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 { ICourse, IUnit, IVideo, IQuiz } from '../course';
import { CourseService } from '../course.service';
import { UserProgressService } from '../../users/user-progress.service';

export class CoursePlayComponent implements OnInit {
  // configurations 
    errorMessage: string;
    course: ICourse;
    public current: IVideo;
    currentUnitQuiz: IQuiz;
    courseId: number;
    totalLessons: number;   // all lessons in the course
    totalQuizzes: number;   // all quizzes in the course
    
    // ... more configs not important for now ...
  
  constructor(private courseService: CourseService,
      private route: ActivatedRoute,
      private router: Router,
      private userProgressService: UserProgressService) {
        userProgressService.connectUser();
       }

  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(id).subscribe(
          course => {
            this.course = course;

            // .. more code here ..

          },
          error  => this.errorMessage = <any>error);
      }
      
    // calculate which quiz is now and save it to currentUnitQuiz
    getQuiz(currentUnitPosition: number) { 
      // ...
    }
    
    // calculate which lesson is now and save it to current
    getCurrent(unitPosition: number, lessonPosition: number) {
      // ...
    }
    
    // .. more functions ...
    

    // EventEmitter from course-lesson component and send the data I need to update
    watched(state) {
      this.userProgressService.addToCompletedLessons(this.course.id, this.current.id,
      this.totalLessons, this.totalQuizzes);
    }
  
    // EventEmitter from course-quiz component and send the data I need to update
    finishedQuiz(state) {
      this.userProgressService.addToCompletedQuizzes(this.course.id, this.currentUnitQuiz.id,
      this.totalLessons, this.totalQuizzes);
    }
    
 }

play.html

<mat-sidenav-container fullscreen *ngIf="course">
  <mat-sidenav class="app-sidenav">
  <!-- more code that's not important for now  -->
  </mat-sidenav>

  <mat-toolbar id="appToolbar">
    <!-- .... -->
  </mat-toolbar>

    <div class="body">
      <course-lesson *ngIf="showLesson == true" [lessonId]="current?.id" [lessonName]="current?.name" [lessonData]="current?.data" [totalLessons]="totalLessons" (clicked)="watched($event)"></course-lesson>
      <quiz-course *ngIf="showQuiz == true" [quiz]="currentUnitQuiz" [minCorrectAnswers]="currentUnitQuiz?.min_correct_answers" (passed)="finishedQuiz($event)"></quiz-course>

        <router-outlet></router-outlet>
    </div>
</mat-sidenav-container>

user-progress.service

import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse, HttpHeaders } from '@angular/common/http';
import { BehaviorSubject } from 'rxjs';
import { Observable, throwError } from 'rxjs';
import { catchError, groupBy } from 'rxjs/operators';
import { LocalStorage } from '@ngx-pwa/local-storage';

import { UserService } from './user.service';
import { AuthUserService } from './auth-user.service';
import { IUser, IUserCourses } from './user';

export class UserProgressService {
      private user: IUser;
      private errorMessage: string;

      constructor(private authUser: AuthUserService, private userService: UserService) { }
      
      // get user from local store
      connectUser() {
        this.user = JSON.parse(localStorage.getItem('user'));
      }
      
      // update user after changes - call the backend again for GET
      updateUser() {
        this.userService.getUser(this.user.id).subscribe(
          user => {
            this.user = user;
            localStorage.setItem('user', JSON.stringify(this.user));

            console.log(this.user); // <--- print the old data, before changes
          },
          error  => this.errorMessage = <any>error
        );
      }
      
      // update complete lessons of a certain course
      addToCompletedLessons(course_id: number, lesson_id: number, totalLessons: number,
      totalQuizzes: number) {
        let userCourses = this.user.user_courses;
        let userLessons;

       // .. actions to know if we need to update or the lesson is already in database

        // add the lesson to database
        const updatedLessons = userLessons + `,${lesson_id}`;
        this.userService.updateCompletedLessons(this.user.id, course_id,
        updatedLessons).subscribe(
          () => {
              console.log("PATCH call successful value returned in body");
          },
          error  => this.errorMessage = <any>error
        );

        // get from backend updated data
        this.updateUser();
      }

      // update complete lessons of a certain course
      addToCompletedQuizzes(course_id: number, quiz_id: number, totalLessons: number,
      totalQuizzes: number) {
        let userCourses = this.user.user_courses;
        let userQuizzes;

        // .. actions to know if we need to update or the quiz is already in database

        // add the quiz to the list
        const updatedQuizzes = userQuizzes + `,${quiz_id}`;
        this.userService.updateCompletedQuizzes(this.user.id, course_id,
        updatedQuizzes).subscribe(
          () => {
              console.log("PATCH call successful value returned in body");
          },
          error  => this.errorMessage = <any>error
        );

        // get from backend updated data
        this.updateUser();
      }

user.service

import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse, HttpHeaders, HttpParams } from '@angular/common/http';
import { BehaviorSubject } from 'rxjs';
import { Observable, throwError } from 'rxjs';
import { catchError, groupBy, tap } from 'rxjs/operators';

import { IUser, IUserCourses } from './user';

const httpOptions = {
  headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};

@Injectable()
export class UserService {

  private url = 'http://localhost:3000/users';


  constructor(private http: HttpClient) {  }

  // Get Single user by id. will 404 if id not found
  getUser(id: number): Observable<IUser> {
    const detailUrl = `${this.url}/${id}` + '.json';

    return this.http.get<IUser>(detailUrl)
        .pipe(catchError(this.handleError));
  }

  // call mark_lesson_as_completed in backend
  updateCompletedLessons(user_id: number, course_id: number, param: any): Observable<any> {
    const userUrl = `${this.url}/${user_id}` + '.json';
    let body = JSON.stringify({
      course_id: course_id,
      completed_lessons: param
    });

    return this.http.patch(userUrl, body, httpOptions)
      .pipe(
        tap(_ => console.log(`updated user ${user_id} with this entry: ${param}`)),
        catchError(this.handleError)
      );
  }

  // call mark_quiz_as_completed in backend
  updateCompletedQuizzes(user_id: number, course_id: number, param: any): Observable <any> {
    const userUrl = `${this.url}/${user_id}` + '.json';
    let body = JSON.stringify({
      course_id: course_id,
      completed_quizzes: param
    });

    return this.http.patch(userUrl, body, httpOptions)
      .pipe(
        tap(_ => console.log(`updated user ${user_id} with this entry: ${param}`)),
        catchError(this.handleError)
      );
  }

  // // Handle Any Kind of Errors
  private handleError(error: HttpErrorResponse) {

    // A client-side or network error occured. Handle it accordingly.
    if (error.error instanceof ErrorEvent) {
      console.error('An error occured:', error.error.message);
    }

    // The backend returned an unsuccessful response code.
    // The response body may contain clues as to what went wrong.
    else {
      console.error(
        'Backend returned code ${error.status}, ' +
        'body was ${error.error}');
    }

    // return an Observable with a user-facing error error message
    return throwError(
      'Something bad happend; please try again later.');
  }
}

1 个答案:

答案 0 :(得分:0)

在我的一个朋友向我解释后,我解决了它。 看起来PATCH和任何添加或编辑数据库的请求都需要花费时间,并且在程序继续执行其他操作的同时,因此在PATCH请求完成之前调用了我从数据库中获取新数据的更新功能。

我所做的就是在订阅内部调用了update函数,就像这样:

        this.userService.updateCompletedLessons(this.user.id, course_id, updatedLessons).subscribe(
          () => {
              console.log("PATCH call successful value returned in body");
              // get from backend updated data
              this.updateUser();
          },
          error  => this.errorMessage = <any>error
        );