Reputation: 1873
I am building a MATERIAL autocomplete for an angular project. Modeling after this Stackblitx... https://stackblitz.com/run?file=src%2Fapp%2Fautocomplete-overview-example.ts
The example creates an array of 5 states. I would like to pull an array of accounts from a service.
The example is clear in its intent. There is an observable on the text control value. When the text control value changes, the observable calls a method to filter the larger array of states into an array where the name contains what has been typed so far into the text box.
I am stumbling on the difference in that I do not have a complete array of accounts. I have an observable of a complete array of accounts.
private _filterStates(value: string): State[] {
const filterValue = value.toLowerCase();
///**** This works b/c states is an array of states
return this.states.filter(state => state.name.toLowerCase().includes(filterValue));
}
private _filterAccount(value: string): COA_Account[] {
const filterValue = value.toLowerCase();
//this is not working because the Observable of Accounts[] does not have a .filter method.
// it isnt an array! its an observable.
return this.Accounts$.filter(acct => acct.name.toLowerCase().includes(filterValue)
);
}
My question is, how do I access the content of the observable in the class. I know how to do it in the html. I feel like I am missing something basic here.
My approach so far is to also define an array and populate that when the observable completes
ngOnInit(): void {
this.Accounts$ = this.myAcctSvc.getCOAByProjectId(4200).pipe(
switchMap((data : COA_Header) =>{
//this works, but Im not sure its the correct way
this.myAccounts = data.Accounts;
return of(this.myAccounts);
}));
}
MY QUESTION IS Is there a way to access the Account[] array via the Accounts$ observable.
Upvotes: 1
Views: 55
Reputation: 623
I would suggest changing your approach to staying in the observable stream as much as possible. It looks like you probably are already subscribing to Accounts$
in the template. That is great. What you can do is use RXJS to manipulate the stream in a way that will react to the input of the user.
I would suggest using a reactive form for your input, and combine the input stream with the accounts stream like so:
form = this.fb.group({ query: [''] });
// Every new query will retrigger this stream
accounts$ = combineLatest([
this.myAcctSvc.getCOAByProjectId(4200),
this.form.controls.query.valueChanges.pipe(
// Start with initial value ('') as valueChanges doesn't emit anything to start
startWith(this.form.controls.query.value)
),
]).pipe(
map(([accounts, query]) =>
// If there is a query, do the filter, else return all accounts query
? accounts.filter((acct) =>
acct.name.toLocaleLowerCase().includes(query)
)
: accounts
)
);
Upvotes: 1