I'm trying to retrieve the user's lat/lon, once, in the create
function of a Yew Component, so that I can do some math and pass useful decisions to child components. I've made the Yew hook "use_geolocation()" work just fine, but that only runs in a function_component, and there doesn't appear to be any straightforward way to use that location in other components.
Then I found this neat tutorial which uses wasm_bindgen and Seed::app::orders::Orders to make a "cheap clone" of the app, and to call the Javascript functions. The bindings look like:
#[wasm_bindgen]
extern "C" {
type GeolocationCoordinates;
#[wasm_bindgen(method, getter)]
fn latitude(this: &GeolocationCoordinates) -> f64;
#[wasm_bindgen(method, getter)]
fn longitude(this: &GeolocationCoordinates) -> f64;
type GeolocationPosition;
#[wasm_bindgen(method, getter)]
fn coords(this: &GeolocationPosition) ->
GeolocationCoordinates;
}
And the function for fetching geolocation, splicing together the chunks of code from Tor Hovland's tutorial:
let (app, msg_mapper) = (orders.clone_app(), orders.msg_mapper());
let geo_callback = move |position: JsValue| {
let pos: GeolocationPosition = position.into();
let coords = pos.coords();
app.update(msg_mapper(Msg::Position(
coords.latitude(),
coords.longitude(),
)));
};
let geolocation = web_sys::window()
.expect("Unable to get browser window.")
.navigator()
.geolocation()
.expect("Unable to get geolocation.");
let geo_callback_function =
Closure::wrap(
Box::new(|pos| geo_callback(pos)) as Box<dyn Fn(JsValue)>
);
geolocation.get_current_position(
&geo_callback_function.as_ref().unchecked_ref()
).expect("Unable to get position");
geo_callback_function.forget();
I attempted this route, but found that adding the line seed = "0.9.1"
into my Cargo.toml produced compile errors, something about a type mismatch between a closure in wasm_bindgen and something in seed. Included here for completeness:
error[E0283]: type annotations needed for `Closure<T>`
--> /home/djmcmath/.cargo/registry/src/github.com-1ecc6299db9ec823/seed-
0.9.1/src/browser/service/routing.rs:87:9
|
87 | let closure = Closure::new(move |event: web_sys::Event| {
| ^^^^^^^
|
= note: cannot satisfy `_: WasmClosure`
note: required by a bound in `Closure::<T>::new`
--> /home/djmcmath/.cargo/registry/src/github.com-1ecc6299db9ec823/wasm-bindgen-
0.2.81/src/closure.rs:251:17
|
251 | T: ?Sized + WasmClosure,
| ^^^^^^^^^^^ required by this bound in `Closure::<T>::new`
help: consider giving `closure` an explicit type, where the type for type parameter
`T` is specified
|
87 | let closure: Closure<T> = Closure::new(move |event: web_sys::Event| {
| ++++++++++++
help: consider specifying the type argument in the function call
|
87 | let closure = Closure::new::<F>(move |event: web_sys::Event| {
| +++++
After beating my head against that brick wall for a while, I decided to just not use Seed, but I don't know of another way to make a "cheap clone" of the app to make the lifetimes work out correctly. Without that, I get the predictable lifetime error on the geo_callback_function:
let geo_callback_function =
Closure::wrap(
Box::new(|pos: JsValue| geo_callback(pos)) as Box<dyn Fn(JsValue)>
);
Error message:
error[E0597]: `geo_callback` does not live long enough
--> src/ferry_route.rs:213:37
|
213 | Box::new(|pos: JsValue| geo_callback(pos)) as Box<dyn Fn(JsValue)>
| ------------------------^^^^^^^^^^^^------
| | | |
| | | borrowed value does not live long enough
| | value captured here
| cast requires that `geo_callback` is borrowed for `'static`
...
221 | }
| - `geo_callback` dropped here while still borrowed
So I'm at a loss, at this point. Seems like fetching user's location would be simpler than all of this. I'm open to any path that makes any of these work. (Definition of work: I can get the user's lat/lon in the create
function of a Yew Component, so that I can do some math and pass useful decisions to child components.)