我创建了一个角度为4的Web应用程序,其数据从firebase读取(通过角度火焰2),但在显示firebase数据的页面上,我必须在数据显示之前刷新页面一次或两次。这不是新数据,而是其现有数据。此外,当我向firebase写入数据时,我在实际写入任何内容之前已经从前端运行了两次该函数。可能是什么问题?
控制器
import { Component, OnInit } from '@angular/core'
//import api service
import { FreeAgentApiService } from '../free-agent-api.service'
//import list item object
import { ListItem } from './listitem'
//import search componenet
import { SearchComponent } from '../search.component'
//import router
import { Router, ActivatedRoute, ParamMap } from '@angular/router'
//import animations
import { moveIn, fallIn, moveInLeft } from '../router.animations'
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.css'],
animations: [moveIn(), fallIn(), moveInLeft()],
//host: {'[@moveIn]': ''}
})
export class DashboardComponent implements OnInit {
//user name
name: any
//state
state: string = ''
//search string
search: String;
//declare filter
filterOptions = ["Status: Active", "Status: Completed", "Status: Cancelled", "Status: Hidden"]
filter = "Status: Active"
//projects array
projects = [];
//inject api service and router into component
constructor(private freeAgentApi: FreeAgentApiService, private router: Router){
this.freeAgentApi.afAuth.authState.subscribe( auth => {
if(auth){
this.name = auth
}
})
}
ngOnInit(){
//init projects array on page load
this.projects = this.freeAgentApi.getAllProjects()
//console.log(this.projects)
}
//function to go to project
openProject(projectName, projectUrl, projectEndDate, clientName){
//router with parameters
this.router.navigate(['project'], {
queryParams: { projectName: projectName, projectUrl: projectUrl, projectEndDate: projectEndDate, clientName}
})
}
}
查看
<!-- header section -->
<div class="header">
<div class="headerItem">
<img class="logo" alt="logo" src="../../assets/images/now-boarding-logo.svg"/>
</div>
<div class="headerItem">
<my-search (onSearchChange)="search = $event"></my-search>
</div>
<div class="headerItem">
<a class="navTop">projects</a>
<a class="navTop">reporting</a>
</div>
</div>
<!-- main section -->
<div class="main" >
<select class="statusfilter" [(ngModel)] = "filter">
<option *ngFor="let f of filterOptions">{{f}}</option>
</select>
<div class="listentry"
*ngFor="let p of projects | statusFilter: filter | searchPipe:'projectName':search"
(click) = "openProject(p.projectName,p.projectUrl,p.endsOn, p.clientName)">
<div class="listentryitem">
<div class="userNameCircle">ML</div>
<p class="project-title">{{p.projectName}}</p>
</div>
<div class="listentryitem-2">
<p class="note-grey">{{ p.clientName }} </p>
</div>
<div class="listentryitem-3">
<input class="dateListItem field" type="text" value="{{p.endsOn | date: 'EEE d MMM'}}" disabled="true"/>
<input class="budgetTimeInput" name="budgetTime" type="text" value="{{p.taskBudgetTime}}" disabled="true">
<progress class="budgetProgressBar" value="{{p.totalTimeLogged}}" max="{{p.taskBudgetTime}}">
{{ p.taskBudgetTime - p.totalTimeLogged }}
</progress>
</div>
</div>
</div>
api致电的提供商
import { Injectable } from '@angular/core';
//import http modules
import { Http, Headers, Response, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/toPromise';
import 'rxjs/add/operator/mergeMap';
//import firebase modules
import { AngularFireDatabase, FirebaseListObservable } from 'angularfire2/database';
import { AngularFireAuth } from 'angularfire2/auth'
import * as firebase from 'firebase/app'
//import list item component
import { ListItem } from './dashboard/listitem'
//import project item object
import { ProjectItem } from './project/projectItem'
@Injectable()
export class FreeAgentApiService {
//inject Http
constructor(private http: Http, public afAuth: AngularFireAuth, public af: AngularFireDatabase) {
}
//function to populate authorization header
createAuthorizationHeader(headers: Headers) {
headers.append('Authorization', 'Bearer 19wUDe8bnIsfuLsa1MhJfblztRj4WIZYCpnc_NQGG');
}
//project item
//project = new ProjectItem()
//array to store projects
//projects = []
//declare array to store tasks
//tasks = []
//decalare array of expenses
//expenses = [];
//declare total tracked time * hourly rate
//totalTracked = 0
//function to get all projects
getAllProjects(): ListItem[]{
let projects = []
//declare headers
let headers = new Headers();
//add headers
this.createAuthorizationHeader(headers);
//make api call and return promise array
this.http.get('https://api.freeagent.com/v2/projects?sort=-updated_at&per_page=100', { headers: headers })
.map((result: Response) => {
//iterate projects list
result.json().projects.forEach(element => {
//varaible to hold single project
let project = new ListItem();
//assign values to list item object, named 'project' here
project.projectName = element.name;
project.status = element.status;
project.endsOn = element.ends_on;
project.clientUrl = element.contact; //use string to get client name
project.projectUrl = element.url; //use string to get timeslipt
//add current project to projects array
projects.push(project);
})
})
//get contacts
.flatMap(() => this.http.get('https://api.freeagent.com/v2/contacts', {headers: headers}) )
.map((res: Response) => res.json() )
.subscribe( (res) => {
//iterate projects array
projects.forEach((project,index) => {
//iterate contacts array
res.contacts.forEach(r => {
//match contact id with project
if(project.clientUrl == r.url){
//assign client name to organisation name
project.clientName = r.organisation_name
}
})
})
})
//get timeslips
/*this.http.get('https://api.freeagent.com/v2/timeslips', {headers: headers })
.map( (res: Response) => res.json())
.subscribe((res) => {
//iterate projects array
projects.forEach(element => {
element.timeLogged = 0
//iterate timeslips
res.timeslips.forEach(element2 => {
//check if project url matches
if(element2.project == element.projectUrl){
//assign remaining time slip (increment)
element.timeLogged += parseFloat(element2.hours)
}
})
})
})*/
this.getFromFirebase(projects)
return projects
}
//function to save projects to firebase
getFromFirebase(projects: any[]){
//get firebase list
let storedProjects = this.af.list('/projects/')
.subscribe((res) => {
//console.log(res)
//check if results array contains values
if(res.length != 0){
//iterate firebaselist
projects.forEach(p => {
//iterate projects arrays
res.forEach( r => {
//check if project is stored in firebase
if(r.projectUrl == p.projectUrl){
//assign time logged
if(r.taskBudgetTime != undefined && r.taskBudgetTime != null) {
p.taskBudgetTime = r.taskBudgetTime
}
if(r.totalTimeLogged != undefined && r.totalTimeLogged != null){
p.totalTimeLogged = r.totalTimeLogged
}
}
})
})
}
})
return projects;
}
//function to sync firebase object with local object
loadProjectToFromFireBase(project){
//specify key, key is last four characters of url
let key = project.projectUrl.substring(project.projectUrl.length - 4)
//get firebase object, user project url as query parameter
let currentProject = this.af.list('projects/', {
query: {
orderByChild: 'projectUrl',
equalTo: project.projectUrl,
limitToFirst: 1,
}
})
.subscribe((res) => {
//check if any fields are undefined and assign value
for(let field in project){
if(typeof project[field] == 'undefined'){
console.log(field + " -> " + project[field])
if(field == 'clientName'){
project[field] = 'n/a'
} else {
project[field] = ''
}
}
}
console.log(project)
//if no results are returned, write object to firebase
if (res.length == 0){
//write project object to firebase
let ref = this.af.list(`projects/`)
.update(key,project)
} else {
project.taskBudgetTime = 0
//get expenses from firebase
//iterate expenses array
project.expenses.forEach(expense => {
//init expense
expense.expenseBudget = 0
//iterate expenses array
res[0].expenses.forEach(ex => {
if(expense.url == ex.url){
expense.expenseBudget = ex.expenseBudget
}
})
})
//get tasks from firebase
//iterate project tasks array
project.tasks.forEach(task => {
//iterate results array and match task
res[0].tasks.forEach(r => {
//check if task exists
if(task.url == r.url){
//load task budget in time
if(r.budgetTime != undefined && r.budgetTime != null){
task.budgetTime = r.budgetTime
}
}
})
//incement billing rate * task budget time
project.totalRateBudgetTime += Math.round(task.billing_rate * task.budgetTime)
//incement total task budget time
project.taskBudgetTime += Math.round(task.budgetTime)
}
)}
})
}
//function to get tasks
getTasks(projectUrl: string){
let project = new ProjectItem()
//declare headers
let headers = new Headers()
//add headers
this.createAuthorizationHeader(headers)
//get tasks from project
this.http.get('https://api.freeagent.com/v2/tasks?project=' + projectUrl, {headers: headers })
.map((res: Response) => {
res.json().tasks.forEach(t => {
//map to local variable
if(t.is_billable){
let task
task = t
project.tasks.push(task)
}
})
})
.flatMap( () => this.http.get('https://api.freeagent.com/v2/timeslips?project=' + projectUrl, {headers: headers }))
.map((res: Response) => res.json())
.subscribe((res) => {
//init task budget time
project.taskBudgetTime = 0
//init total budget rate * total budget time
project.totalRateBudgetTime = 0
//iterate tasks array
project.tasks.forEach((task, index) => {
//add time logged field
task.timeLogged = 0
//load budget time from firebase or init to zero if not exists
task.budgetTime = 0
//iterate timeslips
res.timeslips.forEach(timeslip => {
//check if task url mathes
if(task.url == timeslip.task){
//increment time logged
task.timeLogged += parseFloat(timeslip.hours)
}
})
//increment total tracked time * task billing rate
project.totalTracked += Math.round(task.timeLogged * task.billing_rate)
//increment total time logged for all tasks
project.totalTimeLogged += Math.round(task.timeLogged)
})
})
//console.log(project)
return project
}
//function to get bills (not expenses)
getExpenses(projectUrl: string){
//declare headers
let headers = new Headers();
//add headers
this.createAuthorizationHeader(headers)
//get expenses from project
return this.http.get('https://api.freeagent.com/v2/bills?project=' + projectUrl, {headers: headers })
.map((res) => res.json())
}
//function to get invoices
getInvoices(projectUrl: string){
//declare total invoices
let invoiceTotal = 0;
//declare headers
let headers = new Headers();
//add headers
this.createAuthorizationHeader(headers)
//get invoices from project
return this.http.get('https://api.freeagent.com/v2/invoices?project=' + projectUrl, {headers: headers })
.map((res) => res.json())
}
//funtion to get estimates
getEstimates(projectUrl: string){
//declare headers
let headers = new Headers()
//add headers
this.createAuthorizationHeader(headers)
//get approved estimates
return this.http.get('https://api.freeagent.com/v2/estimates?project=' + projectUrl, {headers: headers})
.map((res) => res.json())
}
//function to extract promise data
private extractData(res: Response) {
let body = res.json();
return body;
}
//function to handle promise errors
private handleErrorPromise (error: Response | any) {
console.error(error.message || error);
return Promise.reject(error.message || error);
}
}
答案 0 :(得分:2)
问题是您希望异步资源是同步的。 Basicallt这就是正在发生的事情:
getAllProject(){
let projects = [];
doAsyncStuffThatTakes30Seconds.subscribe(result => projects = result)
return projects;
}
在您返回项目时,异步内容尚未完成。这就是你没有看到数据的原因。这可能会让你想知道为什么你有时会看到数据。这是因为firebase会缓存结果,直到它发生变化。因此异步内容在处理之前就已完成。
解决方案是返回一个observable并在流中执行所有处理。现在,您可以在组件中订阅以获取数据。