Reputation: 53
I'm new to Angular and the Observables architecture, and I'm having trouble running functions that have asynchronous code.
In the code below, I am using the AngularFire library to obtain information from a basic Firebase Realtime Database. However, when I call the function searchForCompany()
from one of my components, the observable doesn't load the required data instantly, meaning the HTML elements of my component don't get loaded properly. Am I using the Observables architecture wrong?
import { SubscriptionData } from './interface'
import { Injectable } from '@angular/core';
import { AngularFireDatabase, AngularFireList } from '@angular/fire/database'
@Injectable({
providedIn: 'root'
})
export class SubscriptionService {
private dbRead: SubscriptionData[];
private subscriptionData = new SubscriptionData;
private databasePath = "/companies";
private databaseRef: AngularFireList<SubscriptionData>;
constructor(private _database: AngularFireDatabase) {
this.databaseRef = _database.list(this.databasePath);
}
searchForCompany(service:String) {
for (let key of this.dbRead) {
//Search for name of a company in the Firebase database
if (key.name == service) {
this.subscriptionData=key;
return;
}
}
readDatabase() {
this.databaseRef.valueChanges().subscribe(data=> {
this.dbRead = data;
})
}
}
Upvotes: 1
Views: 156
Reputation: 759
think about observable like about a stream that provides data. Your component should subscribe to this stream. Then a component will receive every new value from the stream.
Some example here:
@Component({
selector: 'app-users-listing',
templateUrl: './users-listing.component.html',
styleUrls: ['./users-listing.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class UsersListingComponent {
// THIS IS A "STREAM" AND YOU NEED TO SUBSCRIBE TO IT IN THE TEMPLATE OR INSIDE CODE
users$: Observable<UserInterface[]> = this.activatedRoute.data.pipe(
map(data => data.users),
);
constructor(
private activatedRoute: ActivatedRoute,
) { }
}
Let's subscribe to users$
inside the template
<mat-list>
<!-- "users$ | async" creates a subscription -->
<mat-list-item *ngFor="let user of (users$ | async)">
<h3 matLine> {{ user.first_name + ' ' + user.last_name }} </h3>
<p matLine>
<span> {{user.email}} </span>
</p>
</mat-list-item>
</mat-list>
Regarding to your example. Try to change your service to return an Observable from the method and subscribe to it in your component. It could be like
searchForCompany () {
return this.databaseRef.valueChanges()
}
And subscribe to it in the component, transform received data, etc. It may looks like:
export class MyComponent {
constructor (private service: SubscriptionService) {}
ngOnInit(): void {
this.service.searchForCompany().pipe(
// SOME ADDITIONAL LOGIC
// --> WRITE SOME CODE TO DESTROY SUBSCRIPTION HERE <---
).subscribe();
}
}
OR create class property - observable. And subscribe to it in template using async
pipe
export class MyComponent {
propert$ = this.service.searchForCompany().pipe(
// SOME ADDITIONAL LOGIC
)
constructor (private service: SubscriptionService) {}
}
Hope it helps.
Upvotes: 1