-
|
Hello, Thanks |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
|
The I have defined the shape of the API objects in python to make them natural to work with and allow the type checker to help us catch errors. For some APIs where the Javascript object cannot be represented in JSON, it might be necessary to return a modified object on the frontend that can be serialized, however my recommendation is to avoid frontend munging of well defined APIs, to retain consistent API names/types, which will make it easier for others and LLMs to understand and change your code. Here is the complete example: import dataclasses
from typing import TypedDict
import reflex as rx
# Wraps `geolocation.getCurrentPosition` in a Promise for use with rx.call_function.
GEOLOCATION_GET_CURRENT_POSITION_PROMISE = """() => {
return new Promise((resolve, reject) => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
// Happy case: resolve the promise with the position
resolve,
// Error case: resolve the promise with an error object to send to the backend.
(error) => resolve({code: error.code, message: error.message}),
// Options
{
enableHighAccuracy: true, // Request the most accurate location possible
timeout: 5000, // Maximum time (in milliseconds) to wait for a position
maximumAge: 0 // Don't use a cached position; force a new one
}
);
} else {
// Geolocation is not supported by the browser (raises frontend error)
reject(new Error("Geolocation is not supported by this browser."));
}
});
}"""
class GeolocationCoordinates(TypedDict):
"""The geolocation coordinates."""
latitude: float
longitude: float
altitude: float | None
accuracy: float
altitude_accuracy: float | None
heading: float | None
speed: float | None
@dataclasses.dataclass(frozen=True)
class GeolocationPosition:
"""The geolocation position."""
coords: GeolocationCoordinates | None = None
timestamp: int | None = None
# Included if the request fails
code: int | None = None # 1 = PERMISSION_DENIED, 2 = POSITION_UNAVAILABLE, 3 = TIMEOUT
message: str | None = None
class State(rx.State):
last_latlon: rx.Field[list[float]] = rx.field(default_factory=list)
last_timestamp: rx.Field[int | None] = rx.field(default=None)
last_error_code: rx.Field[int | None] = rx.field(default=None)
last_error_message: rx.Field[str | None] = rx.field(default=None)
@rx.event
def receive_position(self, position: GeolocationPosition) -> None:
"""Receive the position from the frontend and print it.
Args:
position: The geolocation position.
"""
if position.code is not None:
print(f"Error getting position: {position.code} - {position.message}")
self.last_error_code = position.code
self.last_error_message = position.message
return
print(f"Received position: {position}")
if position.coords is not None:
self.last_error_code = None
self.last_error_message = None
self.last_timestamp = position.timestamp
self.last_latlon = [
position.coords["latitude"],
position.coords["longitude"],
]
else:
self.last_error_message = "Unknown error: No coordinates received."
def index() -> rx.Component:
return rx.container(
rx.color_mode.button(position="top-right"),
rx.vstack(
rx.cond(
State.last_error_message | State.last_error_code.is_not_none(),
rx.callout(
text=f"Error {State.last_error_code}: {State.last_error_message}",
icon="circle-x",
color_scheme="red",
),
),
rx.cond(
State.last_timestamp,
rx.vstack(
rx.text(
"Your position at: ",
rx.moment(State.last_timestamp),
),
rx.text(
f"Latitude {State.last_latlon[0]}, "
f"Longitude {State.last_latlon[1]}"
),
),
rx.text("Click the button to get your position."),
),
rx.button(
"Where am I?",
on_click=rx.call_function(
GEOLOCATION_GET_CURRENT_POSITION_PROMISE,
callback=State.receive_position,
),
),
),
)
app = rx.App()
app.add_page(index) |
Beta Was this translation helpful? Give feedback.
The
getCurrentPositionAPI [1] is a little tricky to wrap because it acceptssuccessanderrorcallback functions rather than being awaitable itself. So to make it work withcall_function'scallbackmechanism, we need to wrap it in our ownPromisewhich Reflex frontend will await for before sending the result to the backend where we will pick it apart with an event handler.I have defined the shape of the API objects in python to make them natural to work with and allow the type checker to help us catch errors. For some APIs where the Javascript object cannot be represented in JSON, it might be necessary to return a modified object on the frontend that can be serialized, however my recomm…