简体   繁体   English

我想分配一个变量的内容,我用 firebase 订阅的数组填充

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

i want to assign the content of a variable i filled with an array of an firebase subscription, my problem is i cant assign the value which i created inside the subscription.我想分配一个变量的内容,我用 firebase 订阅的数组填充,我的问题是我无法分配我在订阅中创建的值。 it feels like i cant use the created value outsite of the subcription(from angularfirestore).感觉我不能在订阅之外使用创造的价值(来自 angularfirestore)。 i know how to use the created variable inside the.html file, but i need it inside the componentclass.我知道如何在 .html 文件中使用创建的变量,但我需要在组件类中使用它。 PS:these files were created with the angular schemantics "ng generate @angular/material:table " 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>

You've forgotten that api calls take time to complete.您忘记了 api 调用需要时间才能完成。 You can't print the user if you haven't got your data back yet!如果您还没有取回数据,则无法打印用户!

For example this will work:例如,这将起作用:

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

Javascript does not wait for subscriptions to complete, it executes other code in the meantime. Javascript 不等待订阅完成,同时执行其他代码。 It is single threaded, but it pushes an action to the back of a queue that says: check if we have received a response yet - if not continue with other code execution.它是单线程的,但它会将一个操作推送到队列的后面:检查我们是否已收到响应 - 如果没有继续执行其他代码。 That's how it makes asynchronous calls non-blocking .这就是它如何使异步调用成为非阻塞的

So you will subscribe, execute all the rest of the code you have pushed onto the stack (ie. your constructor), then it will start checking the queue for operations, which includes checking to see if the api has responded.因此,您将订阅、执行您已压入堆栈(即您的构造函数)的代码的所有 rest,然后它将开始检查队列中的操作,其中包括检查 api 是否已响应。 Only if the api has responded will the callback function from subscribe execute.只有当 api 响应了, subscribe的回调 function 才会执行。 Otherwise it will push this check to the back of the queue again.否则它会再次将此检查推到队列的后面。

To read more about how Javascript asynchronous code works:要阅读有关 Javascript 异步代码如何工作的更多信息:

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


The best way to do something after a subscription callback is to simply put whatever you want to do into a function, and call it at the end of your subscription.在订阅回调后做某事的最佳方法是简单地将您想做的任何事情放入 function,并在订阅结束时调用它。

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

However, if you insist on blocking your code execution to wait for a response, you can use async / await .但是,如果您坚持阻止代码执行以等待响应,则可以使用async / await RXJS has firstValueFrom() to receive a Promise that resolves after receiving one response. RXJS 有firstValueFrom()接收一个Promise ,它在收到一个响应后解析。

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

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

But heed the warning from firstValueFrom() - this is an example of why it is better to use observables over promises.但请注意来自firstValueFrom()的警告——这是一个示例,说明为什么使用可观察对象优于承诺。

If the observable stream completes before any values were emitted, the returned promise will reject with EmptyError or will resolve with the default value if a default was specified.如果可观察对象 stream 在发出任何值之前完成,则返回的 promise 将因 EmptyError 被拒绝,或者如果指定了默认值,则将使用默认值解析。

If the observable stream emits an error, the returned promise will reject with that error.如果可观察对象 stream 发出错误,则返回的 promise 将因该错误而拒绝。

WARNING: Only use this with observables you know will emit at least one value, OR complete.警告:仅将此与您知道会发出至少一个值或完整值的可观察对象一起使用。 If the source observable does not emit one value or complete, you will end up with a promise that is hung up, and potentially all of the state of an async function hanging out in memory. To avoid this situation, look into adding something like timeout, take, takeWhile, or takeUntil amongst others.如果源 observable 没有发出一个值或没有完成,您将以挂起的 promise 结束,并且可能挂起 memory 中挂起的异步 function 的所有 state。为避免这种情况,请考虑添加类似超时的内容、take、takeWhile 或 takeUntil 等等。

source: https://rxjs.dev/api/index/function/firstValueFrom来源: https://rxjs.dev/api/index/function/firstValueFrom


If you wanted to add a five second timeout and some error handling it would look like this:如果你想添加一个五秒的超时和一些错误处理,它看起来像这样:

  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.

相关问题 当我想对数组进行排序时,数组已在初始化后填充 - Array already filled after initialization when i want to sort an array 如何在可观察的 Firebase 变量中分配 SnapshotChanges? - How Can I assign the SnapshotChanges in a Observable Firebase Variable? 我想访问位于component.ts中的更新变量,并将其分配给方法外的其他变量。 - I want to access the update variable which is in component.ts and i want to assign it to other variable outside the method.How to do it 当 ngOnDestroy 在角度时,我应该将 null 分配给订阅吗? - should i assign null to the subscription when ngOnDestroy in angluar? 如何将所有组件订阅分配为单个变量(如数组)并取消订阅所有内容 - How to assign all the component subscription into single variable like array and unsubscribe everything 如何为订阅内的变量赋值? - How to assign a value to variable inside subscription? 无法将订阅结果分配给引用的数组 - Unable to assign result from subscription to referenced array 如果我重新分配一个存储 rxjs 订阅的变量,会取消订阅吗? - If I reassign a variable which stores an rxjs subscription, does that unsubscribe? 我想在表格中显示一个带有嵌套数组的数组 - I want to display in a table an array with nested array 将变量指定为Array中的键 - Assign a variable as key in an Array
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM