【问题标题】:Angular firebase why same function only works once?Angular firebase 为什么相同的功能只能工作一次?
【发布时间】:2018-03-27 23:13:44
【问题描述】:

我得到了 upload.service 和 2 个带有一些组件的不同模块。

upload.service , upload.ts 导入到组件中->

上传.module (

upload.component(一切正常(我可以上传并获取照片) 来自数据库的url数据)

)

ui.module)

upload.component(相同的功能,但我看不到照片,没有网址)

)

工作组件(upload.component):

import { Component, OnInit } from '@angular/core';

import { UploadService } from '../shared/upload.service';
import { Upload } from '../shared/upload';

import { Observable } from 'rxjs/Observable';

@Component({
  selector: 'uploads-list',
  templateUrl: './uploads-list.component.html',
  styleUrls: ['./uploads-list.component.scss'],
})
export class UploadsListComponent implements OnInit {

  uploads: Observable<Upload[]>;
  showSpinner = true;

  constructor(private upSvc: UploadService) { }

  ngOnInit() {
    this.uploads = this.upSvc.getUploads();
    this.uploads.subscribe(() => this.showSpinner = false);
  }
}

组件不工作(ui.component 0 错误):

import {Component, OnInit} from '@angular/core';
import { UploadService } from "../../uploads/shared/upload.service";
import { Upload } from "../../uploads/shared/upload";
import { Observable } from "rxjs/Observable";

@Component({
  selector: 'top-nav',
  templateUrl: './top-nav.component.html',
  styleUrls: ['./top-nav.component.scss'],
})
export class TopNavComponent implements OnInit {
  uploads: Observable<Upload[]>;
  show = false;
  showSpinner = true;
  toggleCollapse() {
    this.show = !this.show;
  }

  constructor(private upSvc: UploadService) { }

  ngOnInit() {
    this.uploads = this.upSvc.getUploads();
    console.log("paimama upload :", this.uploads)
    this.uploads.subscribe(() => this.showSpinner = false);
  }

}

我认为主要问题是我试图在两个不同的模块(组件)中使用来自一项服务的这些函数和变量。如何检索它以便它可以工作?

编辑(我正在调用的函数):

 getUploads() {
    this.uploads = this.db.list(`${this.auth.userId}`).snapshotChanges().map((actions) => {
      return actions.map((a) => {
        const data = a.payload.val();
        const $key = a.payload.key;
        return { $key, ...data };
      });

    });
    return this.uploads;
  }

Html(在upload.component中工作):

<h3>File Uploads</h3>

<div *ngFor="let upload of uploads | async">
  <upload-detail [upload]='upload'></upload-detail>
  <img src="{{upload.url}}" alt="">
</div>

<loading-spinner *ngIf="showSpinner"></loading-spinner>

<hr>

<upload-form></upload-form>

HTML(不工作的 ui.component)

<div *ngFor="let upload of uploads | async">
      <img src="{{upload.url}}" alt="">
    </div>

【问题讨论】:

  • 你的 UploadService 是什么类型的 observable?它可以多次发出值吗?
  • 已编辑:我从上传服务调用的函数。
  • 您在每次调用时都创建了一个新的 observable。在您的服务中创建一个属性并将可观察对象设置为该属性,然后您可以在组件中使用该可观察对象,以便它们共享相同的流。 this.uploads的范围只在每个getUploads调用的内容中。
  • 您能用我的代码示例解释一下吗?抱歉,还是没听懂。
  • 我将在答案中展示示例。

标签: javascript angular firebase firebase-realtime-database


【解决方案1】:

每次调用getUploads() 方法时,您似乎都在重新初始化您的可观察服务。这会导致每个组件订阅不同的 observable,因此它们不会同步。

如果您希望所有组件订阅同一个流,请不要这样做。

改变这个:

getUploads() {
    this.uploads = this.db.list(`${this.auth.userId}`).snapshotChanges().map((actions) => {
        return actions.map((a) => {
            const data = a.payload.val();
            const $key = a.payload.key;
            return { $key, ...data };
        });

    });

    return this.uploads;
}

至此:

getUploads() {
    if (!this.uploads) {
        this.uploads = this.db.list(`${this.auth.userId}`).snapshotChanges().map((actions) => {
            return actions.map((a) => {
                const data = a.payload.val();
                const $key = a.payload.key;
                return { $key, ...data };
            });
        });
    }

    return this.uploads;
}

现在每个组件都应该获得完全相同的可观察流。

如果这没有帮助,请告诉我。


更新:

您可以采取的另一种方法是创建自定义主题并将其用作可观察对象。在两个组件中订阅该 observable,当您从数据库获取上传时,您可以将上传添加到流中。每个组件都会获得您添加到该流的上传。

@Injectable()
export class UploadService {
    uploadSubject: ReplaySubject<Upload> = new ReplaySubject();
    upload$: Observable<Upload> = this.uploadSubject.asObservable();

    getUploads() {
        this.http.get(url).subscribe((upload: Upload) => {
            this.uploadSubject.next(upload);
        });
    }
}

现在在 any 组件中,您只需订阅upload$,并且任何时候调用getUploads(),订阅upload$ 的每个组件都将获得价值。

export class Component1 {
    upload: Upload;

    constructor(private uploadService: UploadService) {
        uploadService.upload$.subscribe((upload: Upload) => this.upload = upload);
    }
}

export class Component2 {
    upload: Upload;

    constructor(private uploadService: UploadService) {
        uploadService.upload$.subscribe((upload: Upload) => this.upload = upload);
    }
}

使用这种方法,只需确保在某处调用getUploads,因为组件不会调用它;他们只是在监听它将广播的值。


更新 2:

现在我正在修改您的代码以使用我上面的示例。由于这是使用您的代码,因此它可能无法正常工作,因为我可能会遗漏您在您的环境中拥有的某些东西。但是上面的原始“更新”可以 100% 工作,因此请以此为指导让您的代码正常工作。只需阅读代码并确保您了解它的作用,您就会发现它适用于您正在做的事情。

上传服务:

@Injectable()
export class UploadService {
    uploadStream: ReplaySubject<Upload[]> = new ReplaySubject();
    uploads$: Observable<Upload[]> = this.uploadStream.asObservable();

    constructor() {
        this.getUploads();
    }

    getUploads() {
        this.db.list(`${this.auth.userId}`)
            .map((actions: Action[]) => {
                return actions.map((action: Action) => {
                    const data = action.payload.val();
                    const $key = action.payload.key;

                    return new Upload({ $key, ...data });
                });
            })
            .subscribe((uploads: Upload[]) => {
                this.uploadStream.next(uploads);
            });
    }
}

上传列表组件:

import { Component } from '@angular/core';

import { UploadService } from '../shared/upload.service';

@Component({
  selector: 'uploads-list',
  templateUrl: './uploads-list.component.html',
  styleUrls: ['./uploads-list.component.scss'],
})
export class UploadsListComponent {
  constructor(public uploadService: UploadService) {}
}

UploadListComponent 模板:

<h3>File Uploads</h3>

<div *ngFor="let upload of uploadService.uploads$ | async">
  <upload-detail [upload]='upload'></upload-detail>
  <img src="{{upload.url}}" alt="">
</div>

<loading-spinner *ngIf="showSpinner"></loading-spinner>

<hr>

<upload-form></upload-form>

现在您可以在第二个组件上采用与上述相同的组件方法。

【讨论】:

  • 不,那没用。现在尝试只在我想使用该文件的组件中包含另一个组件。 。显示另一个组件中的几乎所有内容,但来自数据库的数据除外。
  • 好的,你能一步一步解释应该发生什么吗?也许我误解了你的问题。例如:1. 从数据库加载照片,2. 这样做,3. 结果应该会发生。请尽量做到简洁明了。
  • 我做了一个服务,可以上传文件,上传他们的名字,url到数据库,然后显示文件url。所以我的功能是:从数据库中获取数据(网址、名称等)。
  • @Andrius La。然后你为它创建一个对象对吗?导出类 UploadFiles { url: string;名称:字符串; ... }
  • Upload.service : 1.Uploads photo to storage 2. 将数据保存到 Object 3. 从 Object 获取数据。 Upload.service 使用 upload.ts 作为我编写的接口(键、名称、url 等)
猜你喜欢
  • 2019-10-08
  • 1970-01-01
  • 2021-03-30
  • 1970-01-01
  • 1970-01-01
  • 2018-05-20
  • 1970-01-01
  • 2021-01-15
  • 2021-11-18
相关资源
最近更新 更多