[英]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.