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

时间:2017-08-11 09:47:12

标签: angular angularfire2

我创建了一个角度为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);
  } 
}

1 个答案:

答案 0 :(得分:2)

问题是您希望异步资源是同步的。 Basicallt这就是正在发生的事情:

getAllProject(){
    let projects = [];

    doAsyncStuffThatTakes30Seconds.subscribe(result => projects = result)

    return projects;
}

在您返回项目时,异步内容尚未完成。这就是你没有看到数据的原因。这可能会让你想知道为什么你有时会看到数据。这是因为firebase会缓存结果,直到它发生变化。因此异步内容在处理之前就已完成。

解决方案是返回一个observable并在流中执行所有处理。现在,您可以在组件中订阅以获取数据。