Запрос одного объекта Firebase по ключу из службы

#angular #firebase #firebase-realtime-database #angularfire2

#angular #firebase #firebase-база данных в реальном времени #angularfire2

Вопрос:

Я использую Angular CLI Firebase AngularFire2 и пытаюсь выяснить, как запросить один объект из Firebase с помощью ключа.

Основным потоком было бы отображение списка элементов, затем щелчок по элементу привел бы к подробному представлению для этого конкретного элемента.

Это должно быть довольно распространенным вариантом использования, но в документах AngularFire 2, похоже, нет четких примеров того, как я мог бы это сделать.

Я пытаюсь использовать сервис для запроса элементов, но я не могу заставить его работать.

Компонент

 // COMPONENT

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Router, ActivatedRoute, Params } from '@angular/router';
import { AngularFire, FirebaseObjectObservable} from 'angularfire2';
import { Subscription } from 'rxjs';
import { ItemsService } from '../items.service';

@Component({
  selector: 'app-item-detail',
  templateUrl: './item-detail.component.html',
  styleUrls: ['./item-detail.component.css']
})
export class ItemDetailComponent implements OnInit, OnDestroy {

  private subscription: Subscription;
  private item;

  constructor(private af: AngularFire,
              private route: ActivatedRoute,
              private router: Router,
              private itemsService: ItemsService) { }


  ngOnInit() {
    this.subscription = this.route.params.subscribe(
      (param: any) => {
        let id = param['id'];
        console.log('Key: '  id);
        this.item = this.itemsService.getItem(id);
      }
    );
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }

}
  

Обслуживание

 import { Injectable } from '@angular/core';
import { Headers, Http, Response } from "@angular/http";
import { AngularFire, FirebaseObjectObservable, FirebaseListObservable, FirebaseApp } from 'angularfire2';
import 'rxjs/Rx';

@Injectable()
export class ItemsService {

  private items: FirebaseListObservable<any[]>;
  private item: FirebaseObjectObservable<any>;

  constructor(private af: AngularFire) {}

  getItems(num) {
    this.items = this.af.database
      .list('/items', { query: { limitToLast: num | 20} } )
      .map( (arr) => { return arr.reverse() } ) as FirebaseListObservable<any[]>;
    return this.items;
  }

  getItem(id: string) {
    this.item = this.af.database.object('/items/' id);
    this.item.subscribe(item => {
        console.log(item);
        return item;
      });
  }

}
  

Ответ №1:

Это должно сделать это:

 // COMPONENT

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Router, ActivatedRoute, Params } from '@angular/router';
import { AngularFire, FirebaseObjectObservable} from 'angularfire2';
import { Subscription } from 'rxjs';
import { ItemsService } from '../items.service';

@Component({
  selector: 'app-item-detail',
  templateUrl: './item-detail.component.html',
  styleUrls: ['./item-detail.component.css']
})
export class ItemDetailComponent implements OnInit, OnDestroy {

  private subscription: Subscription;
  private item;

  constructor(private af: AngularFire,
              private route: ActivatedRoute,
              private router: Router,
              private itemsService: ItemsService) { }

  
  ngOnInit() {
    // get id synchronously, don't need it more then once
    const key: string;
    this.route.params.take(1).subscribe(param => key = param["id"]);
    this.subscription = this.itemsService.getItem(id)
      .subscribe(item => this.item = item)
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }

}


@Injectable()
export class ItemsService {
  ...

  getItem(id: string) {
return this.af.database.object('/items/' id);
  }

}  

Попробуйте подписаться на наблюдаемый объект, где вам нужны данные. Ваши методы обслуживания должны возвращать Observable, а не Subscription (если у вас действительно нет веских оснований поступать иначе).

Комментарии:

1. Спасибо за это. Я изменил const на let, поскольку он продолжал жаловаться, что объявления ‘const’ должны быть инициализированы и использовать GetItem (ключ), а не ID. Мне также пришлось объявить private item = {} . Сейчас он работает, однако я получаю задержку в 5-7 секунд до появления данных.

2. Остальная часть страницы загружается довольно быстро, но общее время составляет 10-11 секунд. Не уверен, что это медленная локальная настройка разработчика или это просто не очень хороший способ запроса объекта. Объем данных тривиален, в образце данных всего 8 текстовых узлов. Представление списка загружает те же данные в данный момент, и это намного быстрее. Разве мы не должны извлекать объекты по $key из Firebase?

3. Это проблема CLI github.com/angular/angular-cli/issues/1980 , как только вы загрузите предварительно скомпилированное приложение на сервер, это будет быстро. Вы можете проверить в Dev Tools> Network, затем отфильтровать, чтобы показывать только трафик WebSocket (WS)…

4. Я проверил сетевые настройки, и проблема не в размере сборки (хотя это 4 МБ). Приложение загружается примерно за 4 секунды, а затем для завершения работы Websocket требуется еще 8-10 секунд, что мне показалось странным. Я попытаюсь загрузить его и посмотреть, есть ли такая же задержка в трафике веб-сокета