刷新以显示来自Firebase + Angular 4的内容

问题描述:

我创建了一个角度为4的web应用程序,其中包含从firebase(通过angular fire 2)读取的数据,但在显示firebase数据的页面上,我必须刷新页面一次或数据显示前两次。这不是新数据,也不是现有数据。另外,当我将数据写入Firebase时,在实际写入任何内容之前,我已经从前端运行了两次函数。可能是什么问题呢?刷新以显示来自Firebase + Angular 4的内容

控制器

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); 
    } 
} 
+3

当您询问有关由您的代码引起的问题的问题时,如果您提供可用于重现问题的代码,您将得到更好的答案。该代码应该是...... **最小** - 尽可能使用尽可能少的代码,仍然会产生相同的问题。要经历的代码越多,人们发现问题的可能性就越小。请参见[如何创建最小,完整和可验证的示例](https://*.com/help/mcve)。 – georgeawg

亲瑕疵是你期待异步资源是同步的。 Basicallt这是发生了什么:

getAllProject(){ 
    let projects = []; 

    doAsyncStuffThatTakes30Seconds.subscribe(result => projects = result) 

    return projects; 
} 

在您返回项目的时候,异步的东西还没有完成。这就是为什么你没有看到数据。这可能让你想知道为什么你有时会看到数据。这是因为firebase缓存结果直到它发生变化。所以异步的东西在处理之前完成。

解决的办法是返回一个observable并完成流中的所有处理。现在您可以在您的组件中订阅以获取数据。

+0

我明白你在说什么,但我不知道如何构造代码。有一个http请求从'free agent api'获得信息,我必须在调用firebase之前先返回这些信息,因为要加载的firebase信息与此信息相关联。我将如何在可观察的情况下实现这一目标? –

+0

您可以使用'switchMap'。例如:'http.get('someUrl1).switchMap(someValue => http.get(someValue))' –

+0

谢谢,让我试试这个并且回复你 –