Я создал сервис для некоторых манипуляций, которые должны произойти до вызова функции drawPoll ().Я добавил консольные журналы, чтобы отслеживать порядок выполнения и не могу понять, почему функция, связанная с .then (), выполняет ДО того, как итерация forEach внутри обещания завершится.Весь смысл создания службы и включения манипуляции forEach в обещание заключался в том, чтобы я мог быть абсолютно уверен, что итерация forEach завершена до вызова функции drawPoll ().Что мне здесь не хватает?
poll.component.ts
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import * as Chart from 'chart.js';
import { Observable } from 'rxjs';
import { FirebaseService } from '../services/firebase.service';
import { first } from 'rxjs/operators';
import { CardModule } from 'primeng/card';
import { AngularFireAuth } from '@angular/fire/auth';
import nflPollTypes from '../../assets/types/poll-types-nfl.json';
import nflScoringTypes from '../../assets/types/scoring-types-nfl.json';
@Component({
selector: 'app-poll',
templateUrl: './poll.component.html',
styleUrls: ['./poll.component.scss']
})
export class PollComponent implements OnInit {
chart:any;
poll:any;
votes:[] = [];
labels:string[] = [];
title:string = "";
isDrawn:boolean = false;
inputChoices:any = [];
username:string = "";
points:number;
uid:string = "";
votedChoice:string;
hasVoted:boolean = false;
scoringTypeString:string;
nflPollTypes:any = nflPollTypes.types;
nflScoringTypes:any = nflScoringTypes.types;
@Input()
pollKey: string;
@Input()
pollDocument:any;
@Output()
editEvent = new EventEmitter<string>();
@Output()
deleteEvent = new EventEmitter<string>();
constructor(private firebaseService: FirebaseService, private afAuth: AngularFireAuth) { }
ngOnInit() {
const pollData:any = this.pollDocument.payload.doc;
this.pollKey = pollData.id;
this.poll = {
id: this.pollKey,
helperText: pollData.get("helperText"),
pollType: pollData.get("pollType"),
scoringType: pollData.get("scoringType"),
user: pollData.get("user")
};
this.firebaseService.initPoll(this.pollKey, this.isDrawn, this.drawPoll).then((choices, votedChoice) => {
this.poll.choices = choices;
this.votedChoice = votedChoice;
this.drawPoll();
})
}
drawPoll() {
console.log("DRAW!", this.poll);
if (this.isDrawn) {
this.chart.data.datasets[0].data = this.poll.choices.map(choice => choice.votes);
this.chart.data.datasets[0].label = this.poll.choices.map(choice => choice.text);
this.chart.update()
}
if (!this.isDrawn) {
this.inputChoices = this.poll.choices;
var canvas = <HTMLCanvasElement> document.getElementById(this.pollKey);
if(canvas) {
var ctx = canvas.getContext("2d");
this.chart = new Chart(ctx, {
type: 'horizontalBar',
data: {
labels: this.poll.choices.map(choice => choice.text),
datasets: [{
label: this.title,
data: this.poll.choices.map(choice => choice.votes),
fill: false,
backgroundColor: [
"rgba(255, 4, 40, 0.2)",
"rgba(19, 32, 98, 0.2)",
"rgba(255, 4, 40, 0.2)",
"rgba(19, 32, 98, 0.2)",
"rgba(255, 4, 40, 0.2)",
"rgba(19, 32, 98, 0.2)"
],
borderColor: [
"rgb(255, 4, 40)",
"rgb(19, 32, 98)",
"rgb(255, 4, 40)",
"rgb(19, 32, 98)",
"rgb(255, 4, 40)",
"rgb(19, 32, 98)",
],
borderWidth: 1
}]
},
options: {
events: ["touchend", "click", "mouseout"],
onClick: function(e) {
console.log("clicked!", e);
},
tooltips: {
enabled: true
},
title: {
display: true,
text: this.title,
fontSize: 14,
fontColor: '#666'
},
legend: {
display: false
},
maintainAspectRatio: true,
responsive: true,
scales: {
xAxes: [{
ticks: {
beginAtZero: true,
precision: 0
}
}]
}
}
});
this.isDrawn = true;
}
}
}
}
firebase.service.ts
import { Injectable } from '@angular/core';
import { AngularFirestore } from '@angular/fire/firestore';
import { map, switchMap, first } from 'rxjs/operators';
import { Observable, from } from 'rxjs';
import * as firebase from 'firebase';
import { AngularFireAuth } from '@angular/fire/auth';
@Injectable({
providedIn: 'root'
})
export class FirebaseService {
// Source: https://github.com/AngularTemplates/angular-firebase-crud/blob/master/src/app/services/firebase.service.ts
constructor(public db: AngularFirestore, private afAuth: AngularFireAuth) { }
initPoll(pollKey, isDrawn, drawPollCallback) : any {
return new Promise((resolve, reject) => {
let votedChoice;
let choices = [];
this.getChoices(pollKey).pipe(first()).subscribe(fetchedChoices => {
fetchedChoices.forEach(choice => {
const choiceData:any = choice.payload.doc.data();
const choiceKey:any = choice.payload.doc.id;
this.getVotes(choiceKey).pipe(first()).subscribe((votes: any) => {
choices.push({
id: choiceKey,
text: choiceData.text,
votes: votes.length,
players: choiceData.players
});
let currentUserId = this.afAuth.auth.currentUser.uid;
let hasVoted = votes.filter((vote) => {
return (vote.payload.doc._document.proto.fields.choice.stringValue == choiceKey) &&
(vote.payload.doc._document.proto.fields.user.stringValue == currentUserId);
});
if (hasVoted.length > 0) {
votedChoice = hasVoted[0].payload.doc._document.proto.fields.choice.stringValue;
}
});
this.getVotes(choiceKey).subscribe((votes: any) => {
if (isDrawn) {
const selectedChoice = choices.find((choice) => {
return choice.id == choiceKey
});
selectedChoice.votes = votes.length;
drawPollCallback();
}
});
});
console.log("Done iterating");
});
resolve(choices, votedChoice)
});
}
}