Having spent some time trying to get my head around using observable's on service functions, I have decided to ask the question on here.
I have a service which is designed around WebUSB in order to make a connection to a device attached to the computer within the browser. The code works but it needs to be better, in that when it calls the function to connect, since it is a pure function, the code continues in the background within the controller regardless of whether or not a device is actually selected.
webSerialService.ts
// Grab and assign a port to the variables this.device.
requestPorts() {
navigator.serial.requestPort(this.filters)
.then(
(result) => {
this.device = result;
// Open up the port.
this.device.open({ baudRate: 9600 });
},
(error) => {
console.log("The user selected the cancel, no port was selected.");
}
);
return this.device;
}
And the receiving controller code:
public connect() {
// Let the user know they are about to do something.
this.displayText = "-----";
try {
// Return the device selected.
this.device = this.webSerialService.requestPorts();
} catch (e) {
console.log(e);
}
// Have we selected a port or not?
if (this.webSerialService.device == false) {
// Let the user know that no port was selected.
this.displayText = "NO PORT";
}
else {
// Let the user know they are connected.
this.displayText = "Awaiting Data";
}
}
The second part of the controller code, obviously executes without waiting for a device to be selected, which is not what I want, but expected. Having tried to turn the service function into an observable and then subscribing to it within the controller, I would get the error message when the "connect" function is fired:
TypeError: Cannot read properties of undefined (reading 'subscribe')
I amended the function definition within the server to:
requestPorts(): Observable<any> {
And then the controller code would be:
this.webSerialService.requestPorts().subscribe(data => {console.log(data)});
Which is where the aforementioned error would occur.
I've tried several various examples found on the internet and on StackOverflow, but I seem to be missing a crucial bit of understanding how Observables work and how to define them for functions.
Thank-you for any input and insight you can provide.
The problem is not in the Observable
itself. The problem is that the moment you return this.device
, it hasn't been assigned a value yet. It's undefined
. Hence the error.
Try converting the Promise
into an Observable
like this instead:
import { from, map } from 'rxjs';
// ...
requestPorts(): Observable<any> {
return from(navigator.serial.requestPort(this.filters)).pipe(
map((result) => {
this.device = result;
this.device.open({ baudRate: 9600 });
return this.device;
})
);
}