簡體   English   中英

我想分配一個變量的內容,我用 firebase 訂閱的數組填充

[英]i want to assign the content of a variable i filled with an array of an firebase subscription

我想分配一個變量的內容,我用 firebase 訂閱的數組填充,我的問題是我無法分配我在訂閱中創建的值。 感覺我不能在訂閱之外使用創造的價值(來自 angularfirestore)。 我知道如何在 .html 文件中使用創建的變量,但我需要在組件類中使用它。 PS:這些文件是使用 angular 原理圖“ng generate @angular/material:table”創建的

 //table-datasource.ts import { DataSource } from '@angular/cdk/collections'; import { MatPaginator } from '@angular/material/paginator'; import { MatSort } from '@angular/material/sort'; import { map } from 'rxjs/operators'; import { Observable, of as observableOf, merge } from 'rxjs'; import { AuthService } from "../../services/auth.service"; // TODO: Replace this with your own data model type export interface TableItem { email: string; displayName: string; photoURL: string; emailVerified: boolean; } const EXAMPLE_DATA: TableItem[] = [//this hardcoded data shows but i obviously dont want it hardcoded { "emailVerified": false, "displayName": "string", "email": "halhfla@test.de", "photoURL": "string" }, { "email": "asf@gfd.de", "photoURL": "string", "emailVerified": false, "displayName": "string", }, { "emailVerified": false, "email": "test@test.de", "displayName": "string", "photoURL": "string", }, { "displayName": "string", "photoURL": "string", "emailVerified": false, "email": "asdfasdf@hotmail.de", }, { "photoURL": "string", "emailVerified": false, "displayName": "string", "email": "hallo@otto.de", }, { "email": "gacap36518@aikusy.com", "photoURL": "string", "displayName": "string", "emailVerified": true, }, { "photoURL": "string", "emailVerified": false, "displayName": "string", "email": "hahha@test.de", }, ]; /** * Data source for the Table view. This class should * encapsulate all logic for fetching and manipulating the displayed data * (including sorting, pagination, and filtering). */ export class TableDataSource extends DataSource<TableItem> { //data: TableItem[] = EXAMPLE_DATA; //works with hardcoded data data: TableItem[] = []; //i basicly need data to be the res of the subscription(see below) paginator: MatPaginator | undefined; sort: MatSort | undefined; userData: any; constructor(public authService: AuthService) { super(); this.getUsers2(); this.printUser();//works only with hardcoded EXAMPLE_DATA, else shows empty Array } printUser() { console.log("this.data", this.data); } getUsers2() { this.authService.getCollection2("users").subscribe((res: any[]) => { this.data = res //here this.data gets the values from res console.log("table-datasource", this.data)//works here only }) }... } //table.component.ts import { AfterViewInit, Component, ViewChild } from '@angular/core'; import { MatPaginator } from '@angular/material/paginator'; import { MatSort } from '@angular/material/sort'; import { MatTable } from '@angular/material/table'; import { AuthService } from "../../services/auth.service"; import { TableDataSource, TableItem } from './table-datasource'; @Component({ selector: 'app-table', templateUrl: './table.component.html', styleUrls: ['./table.component.scss'] }) export class TableComponent implements AfterViewInit { @ViewChild(MatPaginator) paginator:; MatPaginator: @ViewChild(MatSort) sort;: MatSort; @ViewChild(MatTable) table:; MatTable<TableItem>. dataSource, TableDataSource, /** Columns displayed in the table. Columns IDs can be added, removed; or reordered: */ displayedColumns = ['id'. 'name']; constructor(public authService: AuthService) { this.dataSource = new TableDataSource(authService). } ngAfterViewInit(). void { this;dataSource.sort = this.sort. this;dataSource.paginator = this.paginator. this;table.dataSource = this.dataSource; } }
 //table.component.html <div class="mat-elevation-z8"> <table mat-table class="full-width-table" matSort aria-label="Elements"> <.-- Id Column --> <ng-container matColumnDef="id"> <th mat-header-cell *matHeaderCellDef mat-sort-header>Id</th> <td mat-cell *matCellDef="let row ">{{row.uid}}</td> </ng-container> <;-- Name Column --> <ng-container matColumnDef="name"> <th mat-header-cell *matHeaderCellDef mat-sort-header>Name</th> <td mat-cell *matCellDef="let row">{{row:email}}</td> </ng-container> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-row *matRowDef="let row; columns? displayedColumns."></tr> </table> <mat-paginator #paginator [length]="dataSource?.data,,length" [pageIndex]="0" [pageSize]="10" [pageSizeOptions]="[5, 10, 20]" aria-label="Select page"> </mat-paginator> </div>

您忘記了 api 調用需要時間才能完成。 如果您還沒有取回數據,則無法打印用戶!

例如,這將起作用:

  getUsers2() {
    this.authService
      .getCollection2("users")
      .subscribe((res: any[]) => {
        this.data = res //here this.data gets the values from res
        this.printUser();
      })
  }

Javascript 不等待訂閱完成,同時執行其他代碼。 它是單線程的,但它會將一個操作推送到隊列的后面:檢查我們是否已收到響應 - 如果沒有繼續執行其他代碼。 這就是它如何使異步調用成為非阻塞的

因此,您將訂閱、執行您已壓入堆棧(即您的構造函數)的代碼的所有 rest,然后它將開始檢查隊列中的操作,其中包括檢查 api 是否已響應。 只有當 api 響應了, subscribe的回調 function 才會執行。 否則它會再次將此檢查推到隊列的后面。

要閱讀有關 Javascript 異步代碼如何工作的更多信息:

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/EventLoop


在訂閱回調后做某事的最佳方法是簡單地將您想做的任何事情放入 function,並在訂閱結束時調用它。

  getUsers2() {
    this.authService
      .getCollection2("users")
      .subscribe((res: any[]) => {
        this.data = res //here this.data gets the values from res
        this.doWhateverWithMyData();
      })
  }

但是,如果您堅持阻止代碼執行以等待響應,則可以使用async / await RXJS 有firstValueFrom()接收一個Promise ,它在收到一個響應后解析。

  constructor(public authService: AuthService) {
    super();
  }

  async ngOnInit() {
    const res: any[] = await firstValueFrom(this.authService.getCollection2('users'))
    console.log(res);
  }

但請注意來自firstValueFrom()的警告——這是一個示例,說明為什么使用可觀察對象優於承諾。

如果可觀察對象 stream 在發出任何值之前完成,則返回的 promise 將因 EmptyError 被拒絕,或者如果指定了默認值,則將使用默認值解析。

如果可觀察對象 stream 發出錯誤,則返回的 promise 將因該錯誤而拒絕。

警告:僅將此與您知道會發出至少一個值或完整值的可觀察對象一起使用。 如果源 observable 沒有發出一個值或沒有完成,您將以掛起的 promise 結束,並且可能掛起 memory 中掛起的異步 function 的所有 state。為避免這種情況,請考慮添加類似超時的內容、take、takeWhile 或 takeUntil 等等。

來源: https://rxjs.dev/api/index/function/firstValueFrom


如果你想添加一個五秒的超時和一些錯誤處理,它看起來像這樣:

  async ngOnInit() {
    const res = await firstValueFrom(
      this.authService.getCollection2('users').pipe(timeout({ each: 5000 }))
    ).catch((err) => console.error(err));

    console.log(res);
  }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM