I want to create a service that will hold the data received from REST API than emits it to whom ever needs it.
I used BehaviorSubject and managed to get the data in the template (using *ngFor) but whatever I tried, I can't get it in a component. The flow is that a some component calls fetchCustomersDetails than renders the data as a list.
Once the user clicks a customer, the name passed to another page where I wish to filter the data in the service and retrieve the match.
Examine the code shows that the name of the customer (from the list fetched in the service) is passed to getCustomerByCompanyName but the subject contain an empty array where the data needs to be saved.
I'm very new to Angular and it seems I'm missing some concept of using observables.
Thank you for your help. Here is what I tried so far:
/* Service */
export class CustomerDetailsService {
private apiUrl: string = `https://...`;
private readonly customersDetailsPool$: BehaviorSubject<ICustomerDetails[]> = new BehaviorSubject<ICustomerDetails[]>([]);
constructor(private http: HttpClient) { }
fetchCustomersDetails(){
return this.http.get<ICustomerDetails[]>(this.apiUrl)
.subscribe({
next: ((customerDetailsList: ICustomerDetails[]) => this.customersDetailsPool$.next(customerDetailsList)),
error: ((error: any) => this.handleError(error)),
complete: (() => console.log("test: ", this.customersDetailsPool$))
})
}
get customersDetailsPool(): Observable<ICustomerDetails[]> {
return this.customersDetailsPool$.asObservable();
}
getCustomerByCompanyName(name: string) {
console.log("customersDetailsPool: ", this.customersDetailsPool$);
return this.customersDetailsPool$.pipe(
map((customers: ICustomerDetails[]) => {customers.find((customer) => {customer.company === name})})
)
}
}
/* component */
@Component({
selector: 'app-customer-edit-page',
templateUrl: './customer-edit-page.component.html',
styleUrls: ['./customer-edit-page.component.scss'],
providers: [CustomerDetailsService]
})
export class CustomerEditPageComponent implements OnInit, AfterViewInit {
@ViewChild(CustomerDetailsComponent)
private customerNewDetails!: CustomerDetailsComponent;
customerName: string | null = '';
isEdit: boolean = false;
customerDetails: ICustomerDetails = {
company: '',
contacts: [],
};
constructor(
private router: Router,
private route: ActivatedRoute,
public customerDetailsService: CustomerDetailsService,
) { }
ngOnInit(): void {
this.customerName = this.route.snapshot.paramMap.get('company');
this.isEdit = this.isToEdit();
if (this.customerName) {
this.customerDetailsService.getCustomerByCompanyName(this.customerName)
.subscribe((customer) => {
if (customer) {
this.customerDetails = customer;
}
})
.unsubscribe();
}
}
}
CodePudding user response:
You've got a syntax error in your find
call.
customers.find((customer) => {customer.company === name})
This does not return anything, Either add return
or remove the curly braces.
customers.find((customer) => {return customer.company === name})
OR
customers.find((customer) => customer.company === name)
Without braces, return
is implicit.
The way you have it set up, you also need to call fetchCustomerDetails()
at some point, and you can't just unsubscribe immediately, because you have no idea if the initial http request from fetchCustomerDetails()
has completed yet, unless you have a mechanism in place that you haven't showed.
CodePudding user response:
You're immediately unsubscribing from the service observable, which is probably creating some async timing issue
Remove the unsubscribe()
, and instead use a takeUntil
- you can lookup examples of takeUntil
with ngOnDestroy