Reputation: 3259
I'm writing an application in React (react-native actually, but it's not relevant).
I'm using a bluetooth module that perform different actions in the form of chained promises, something like this:
writeData(data) {
this.manager.startDeviceScan(null, null, (error, device) => {
if (error) {
this.store.dispatch({type: "SET_ERROR", payload: error.message})
return
}
if (device.name === 'MyDevice') {
this.store.dispatch({type: "SET_STATUS", payload: "Device found, stopping device scan...\n"})
this.manager.stopDeviceScan();
device.connect().then((device) => {
this.store.dispatch({type: "SET_STATUS", payload: "Device is connected!\n"})
return device.discoverAllServicesAndCharacteristics()
}).then((device) => {
device.writeCharacteristicWithoutResponseForService(
data.serviceId,
data.charId,
data.dataToWrite
).then(res => {
this.store.dispatch({type: "SET_STATUS", payload: `${data.message}!\n`})
device.cancelConnection().then(res => {
this.store.dispatch({type: "SET_STATUS", payload: 'Action dispatched, closing connection\n'})
}).catch(error => {
this.store.dispatch({type: "SET_ERROR", payload: error.message})
})
}).catch(error => {
this.store.dispatch({type: "SET_ERROR", payload: error.message})
})
}).catch((error) => {
this.store.dispatch({type: "SET_ERROR", payload: error.message})
});
}
});
}
Now, to have more flexibility in my application I would like to handle errors and success in the local component where I call this function. So, instead of having this function in a separate file and using it in various component like this:
BleApi.writeData({
serviceId: "ee733136-2de5-4e04-ae81-xxxxxxxxx",
charId: "cde744c6-2966-4b08-84d2-xxxxxxxxx",
dataToWrite: btoa(`${index};${program};0`),
message: "Program has been successfully added.",
})
I would like to return the promise from the connection module, so I can have the then/catch in the local component:
device.connect().then((device) => {
this.store.dispatch({type: "SET_STATUS", payload: "Device is connected!\n"})
return device.discoverAllServicesAndCharacteristics()
}).then((device) => {
// this is the function I would like to return:
return device.writeCharacteristicWithoutResponseForService(
data.serviceId,
data.charId,
data.dataToWrite
)
and then wherever I call this function:
BleApi.writeData({
serviceId: "ee733136-2de5-4e04-ae81-xxxxxxxxx",
charId: "cde744c6-2966-4b08-84d2-xxxxxxxxx",
dataToWrite: btoa(`${index};${program};0`),
message: "Program has been successfully added.",
}).then(res => {}).catch(error => {}) // now I can handle the result/errors here
but with this code I get TypeError: Cannot read property 'then' of undefined
How can I fix this?
EDIT: error in copying the function (it was BleApi both time), plus I want to clarify something that I forgot: I know that BleApi.writeData returns a promise because that's the functon I'm writing. I want it to return a promise and right now it returns undefined. Sorry for not specifying this before
EDIT 2: I guess I missed another piece of relevant information. In the function writeData
everything is wrapped around the function startDeviceScan
of the bluetooth module, and the way I wrote discoverAllServicesAndCharacteristics
is entirely taken form the documentation of the module: https://polidea.github.io/react-native-ble-plx/
Upvotes: 2
Views: 106
Reputation: 1073978
I assume Ble.writeData
/BleApi.writeData
is the function where your device.connect()
code is located? If so, the problem is that you're not returning the promise chain. It's hard to give you a solid answer without more context for the code you've provided, but it would be something like:
writeData() {
return device.connect()
.then((device) => {
this.store.dispatch({type: "SET_STATUS", payload: "Device is connected!\n"})
return device.discoverAllServicesAndCharacteristics();
})
.then((device) => {
return device.writeCharacteristicWithoutResponseForService(
data.serviceId,
data.charId,
data.dataToWrite
);
});
}
(I'm using method syntax there, assuming this is within an object literal or a class.)
...except I suspect you meant for this line:
return device.discoverAllServicesAndCharacteristics();
to be
return device.discoverAllServicesAndCharacteristics().then(() => device);
...since your next then
handler expects to get device
. If so, then:
writeData() {
return device.connect()
.then((device) => {
this.store.dispatch({type: "SET_STATUS", payload: "Device is connected!\n"})
return device.discoverAllServicesAndCharacteristics().then(() => device);
})
.then((device) => {
return device.writeCharacteristicWithoutResponseForService(
data.serviceId,
data.charId,
data.dataToWrite
);
});
}
But note that since you're transpiling with React Native, you can use an async
function so you can write your logical flow with standard flow control constructs rather than .then
and .catch
handlers:
async writeData() {
const device = await device.connect();
this.store.dispatch({type: "SET_STATUS", payload: "Device is connected!\n"})
await device.discoverAllServicesAndCharacteristics();
return device.writeCharacteristicWithoutResponseForService(
data.serviceId,
data.charId,
data.dataToWrite
);
}
Upvotes: 2