Angular Ionic2变更检测问题,忽略第一个变更

Angular Ionic2变更检测问题,忽略第一个变更,angular,ionic2,rxjs,observable,Angular,Ionic2,Rxjs,Observable,我正在用ionic2开发一个测验应用程序。这些问题从数据库中提取,并使用-组件显示。模板的重要部分如下所示: <ion-content padding> ... <ion-slides *ngIf="status === QuizState.running" pager="true" paginationType="progress"> <ion-slide *ngFor="let question of questions; let index =

我正在用ionic2开发一个测验应用程序。这些问题从数据库中提取,并使用
-组件显示。模板的重要部分如下所示:

<ion-content padding>
  ...
  <ion-slides *ngIf="status === QuizState.running" pager="true" paginationType="progress">
    <ion-slide *ngFor="let question of questions; let index = index">
      <span>{{ question|json}}</span>
      ...
    </ion-slide>
  </ion-slides>
  ...
</ion-content>
import { Component, ViewChild, ChangeDetectionStrategy } from '@angular/core';
import { NavController, Slides } from 'ionic-angular';

import { QuizLoaderService, QuizType, QuizDefinition } from '../../components/quiz-item/quiz-loader.service';
import { SamplePipe } from 'ngx-pipes/src/app/pipes/array/sample';
import { ShufflePipe } from 'ngx-pipes/src/app/pipes/array/shuffle';

import { Observable } from 'rxjs';
import 'rxjs/add/observable/from';
import 'rxjs/add/observable/forkJoin';

enum QuizState {
    idle,
    running,
    finished
}

@Component({
    selector: 'page-quiz',
    templateUrl: 'quiz.html',
    providers: [
        SamplePipe, ShufflePipe, QuizLoaderService
    ],
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class QuizPage {

    private slides: Slides;

    private status: QuizState = QuizState.idle;
    private questions: Array<QuizType|QuizDefinition> = [];

    private readonly numberOfQuestions = 10;

    // make enum accessable from the view
    readonly QuizState = QuizState;

    constructor(public navCtrl: NavController, private quizLoaderService: QuizLoaderService) {}

    @ViewChild(Slides) set slidesViewChild(slides: Slides) {

        if(slides) {

            slides.onlyExternal = true;
            slides.ionSlideWillChange.subscribe(slides => {

                // load the after next question in advance
                if(!slides.isEnd()) {

                    let index: number = slides.getActiveIndex() + 1;
                    let quizType: QuizType = <QuizType>this.questions[index];

                    this.quizLoaderService.loadQuizItem(quizType).subscribe((item: QuizDefinition) => this.questions[index] = item);
                }
            });
        }

        this.slides = slides;
    }

    startQuiz() {

        this.status = QuizState.running;
        // generate an array of question types
        this.questions = this.quizLoaderService.getQuizItems(this.numberOfQuestions);

        // fetch data for the first two questions
        let startingQuestions: Observable<QuizDefinition>[] = [0, 1].map(index => {

            let quizType = <QuizType>this.questions[index];

            return this.quizLoaderService.loadQuizItem(quizType);
        });

        Observable.forkJoin(startingQuestions).subscribe(
          // update first two items with actual question data
          (items: QuizDefinition[]) => this.questions.splice(0, items.length, ...items)
        );
    }
    ...
}

...
{{问题| json}}
...
...
组件代码如下所示:

<ion-content padding>
  ...
  <ion-slides *ngIf="status === QuizState.running" pager="true" paginationType="progress">
    <ion-slide *ngFor="let question of questions; let index = index">
      <span>{{ question|json}}</span>
      ...
    </ion-slide>
  </ion-slides>
  ...
</ion-content>
import { Component, ViewChild, ChangeDetectionStrategy } from '@angular/core';
import { NavController, Slides } from 'ionic-angular';

import { QuizLoaderService, QuizType, QuizDefinition } from '../../components/quiz-item/quiz-loader.service';
import { SamplePipe } from 'ngx-pipes/src/app/pipes/array/sample';
import { ShufflePipe } from 'ngx-pipes/src/app/pipes/array/shuffle';

import { Observable } from 'rxjs';
import 'rxjs/add/observable/from';
import 'rxjs/add/observable/forkJoin';

enum QuizState {
    idle,
    running,
    finished
}

@Component({
    selector: 'page-quiz',
    templateUrl: 'quiz.html',
    providers: [
        SamplePipe, ShufflePipe, QuizLoaderService
    ],
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class QuizPage {

    private slides: Slides;

    private status: QuizState = QuizState.idle;
    private questions: Array<QuizType|QuizDefinition> = [];

    private readonly numberOfQuestions = 10;

    // make enum accessable from the view
    readonly QuizState = QuizState;

    constructor(public navCtrl: NavController, private quizLoaderService: QuizLoaderService) {}

    @ViewChild(Slides) set slidesViewChild(slides: Slides) {

        if(slides) {

            slides.onlyExternal = true;
            slides.ionSlideWillChange.subscribe(slides => {

                // load the after next question in advance
                if(!slides.isEnd()) {

                    let index: number = slides.getActiveIndex() + 1;
                    let quizType: QuizType = <QuizType>this.questions[index];

                    this.quizLoaderService.loadQuizItem(quizType).subscribe((item: QuizDefinition) => this.questions[index] = item);
                }
            });
        }

        this.slides = slides;
    }

    startQuiz() {

        this.status = QuizState.running;
        // generate an array of question types
        this.questions = this.quizLoaderService.getQuizItems(this.numberOfQuestions);

        // fetch data for the first two questions
        let startingQuestions: Observable<QuizDefinition>[] = [0, 1].map(index => {

            let quizType = <QuizType>this.questions[index];

            return this.quizLoaderService.loadQuizItem(quizType);
        });

        Observable.forkJoin(startingQuestions).subscribe(
          // update first two items with actual question data
          (items: QuizDefinition[]) => this.questions.splice(0, items.length, ...items)
        );
    }
    ...
}
从'@angular/core'导入{Component,ViewChild,ChangeDetectionStrategy};
从“离子角度”导入{NavController,Slides};
从“../../components/Quit item/Quit loader.service”导入{QuizLoaderService,QuizType,QuizDefinition};
从“ngx pipes/src/app/pipes/array/sample”导入{SamplePipe};
从“ngx pipes/src/app/pipes/array/shuffle”导入{shufflepe};
从“rxjs”导入{Observable};
导入“rxjs/add/observable/from”;
导入“rxjs/add/observable/forkJoin”;
枚举QuizState{
闲置的
跑步
完成
}
@组成部分({
选择器:“页面测验”,
templateUrl:'quick.html',
供应商:[
采样管、ShufflePipe、QuizLoaderService
],
changeDetection:ChangeDetectionStrategy.OnPush
})
导出类QuizPage{
私人幻灯片:幻灯片;
私有状态:QuizState=QuizState.idle;
私人问题:数组=[];
私人只读numberOfQuestions=10;
//使枚举可从视图访问
只读QuizState=QuizState;
构造函数(公共navCtrl:NavController,私有quizLoaderService:quizLoaderService){}
@ViewChild(幻灯片)设置幻灯片ViewChild(幻灯片:幻灯片){
如果(幻灯片){
slides.onlyExternal=true;
slides.ionSlideWillChange.subscribe(幻灯片=>{
//提前加载下一个问题之后的内容
如果(!slides.isEnd()){
let index:number=slides.getActiveIndex()+1;
让quizType:quizType=this.questions[index];
this.quizLoaderService.loadQuizItem(quizType).subscribe((item:QuizDefinition)=>this.questions[index]=item);
}
});
}
this.slides=幻灯片;
}
startQuiz(){
this.status=QuizState.running;
//生成问题类型数组
this.questions=this.quizLoaderService.getQuizItems(this.numberOfQuestions);
//获取前两个问题的数据
让我们开始提问:可观察[]=[0,1]。地图(索引=>{
让quizType=this.questions[index];
返回这个.quizLoaderService.loadQuizItem(quizType);
});
可观察。forkJoin(开始问题)。订阅(
//使用实际问题数据更新前两项
(items:QuizDefinition[])=>this.questions.splice(0,items.length,…items)
);
}
...
}
首先,
questions
数组只填充
QuizTypes
,这样就可以创建幻灯片了。然后从数据库中加载前两个问题的问题数据(
QuizDefinition
)。当进入下一个问题时,我加载问题的数据

在我的电脑上,这与预期的一样有效,但在手机上,当呈现视图或无法识别更改时,第一个问题不会更新。无论如何,
JSONPipe
仍然显示问题类型
QuizType
,而不是问题数据。第一张幻灯片之后的任何幻灯片都能正常工作

编辑
在我的电脑上,我使用了一个数据库模型。没有耽搁。我添加了一个随机延迟,现在它的行为与移动设备上的相同。第一个问题数据没有设置。

我现在解决了这个问题,切换到完全手动控制更改检测,并且只在预期确实会发生更改时运行它

import { Component, ViewChild, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { NavController, Slides } from 'ionic-angular';

import { QuizLoaderService, QuizType, QuizDefinition } from '../../components/quiz-item/quiz-loader.service';
import { SamplePipe } from 'ngx-pipes/src/app/pipes/array/sample';
import { ShufflePipe } from 'ngx-pipes/src/app/pipes/array/shuffle';

import { Observable } from 'rxjs';
import 'rxjs/add/observable/forkJoin';

enum QuizState {
    idle,
    running,
    finished
}

@Component({
    selector: 'page-quiz',
    templateUrl: 'quiz.html',
    providers: [
        SamplePipe, ShufflePipe, QuizLoaderService
    ],
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class QuizPage {

    private slides: Slides;

    private status: QuizState = QuizState.idle;
    private questions: Array<QuizType|QuizDefinition> = [];

    private readonly numberOfQuestions = 10;

    // make enum accessable from the view
    readonly QuizState = QuizState;

    constructor(public navCtrl: NavController, private quizLoaderService: QuizLoaderService, private changeDetectorRef: ChangeDetectorRef) {}

    ngAfterViewInit() {

        // disable change detection
        this.changeDetectorRef.detach();
    }

    ...
    startQuiz() {

        this.status = QuizState.running;
        this.questions = this.quizLoaderService.getQuizItems(this.numberOfQuestions);

        //this.changeDetectorRef.detectChanges();
        // fetch data for the first two questions
        let startingQuestions: Observable<QuizDefinition>[] = [0, 1].map(index => {

            let quizType = <QuizType>this.questions[index];

            return this.quizLoaderService.loadQuizItem(quizType);
        });

        Observable.forkJoin(startingQuestions).subscribe((items: QuizDefinition[]) => {

            this.questions.splice(0, items.length, ...items);
            // run change detection when changes happen
            this.changeDetectorRef.detectChanges();
        });
    }
    ...
}
从'@angular/core'导入{Component,ViewChild,ChangeDetectionStrategy,ChangeDetectorRef};
从“离子角度”导入{NavController,Slides};
从“../../components/Quit item/Quit loader.service”导入{QuizLoaderService,QuizType,QuizDefinition};
从“ngx pipes/src/app/pipes/array/sample”导入{SamplePipe};
从“ngx pipes/src/app/pipes/array/shuffle”导入{shufflepe};
从“rxjs”导入{Observable};
导入“rxjs/add/observable/forkJoin”;
枚举QuizState{
闲置的
跑步
完成
}
@组成部分({
选择器:“页面测验”,
templateUrl:'quick.html',
供应商:[
采样管、ShufflePipe、QuizLoaderService
],
changeDetection:ChangeDetectionStrategy.OnPush
})
导出类QuizPage{
私人幻灯片:幻灯片;
私有状态:QuizState=QuizState.idle;
私人问题:数组=[];
私人只读numberOfQuestions=10;
//使枚举可从视图访问
只读QuizState=QuizState;
构造函数(公共navCtrl:NavController,私有quizLoaderService:quizLoaderService,私有changeDetectorRef:changeDetectorRef){}
ngAfterViewInit(){
//禁用更改检测
this.changeDetectorRef.detach();
}
...
startQuiz(){
this.status=QuizState.running;
this.questions=this.quizLoaderService.getQuizItems(this.numberOfQuestions);
//this.changeDetectorRef.detectChanges();
//获取前两个问题的数据
让我们开始提问:可观察[]=[0,1]。地图(索引=>{
让quizType=this.questions[index];
返回这个.quizLoaderService.loadQuizItem(quizType);
});
Observable.forkJoin(startingQuestions).subscribe((项目:QuizDefinition[])=>{
这个.问题.拼接(0,items.length,…items);
//发生更改时运行更改检测
this.changeDetectorRef.detectChanges();
});
}
...
}