Fork me on GitHub
#luminus
<
2018-02-24
>
feihong02:02:58

it seems that with the way that +re-frame sets things up, extra callbacks get added when you do re-frame.core/dispatch. Generally, this is not a problem, but it makes a difference with certain mobile apis like the mobile version of the web speech api. in order for a call to speechSynthesis.speak() to succeed on mobile safari, it must happen in the event handler for the button you click, not in another callback function. so .speak() calls work fine on my desktop browsers, but they don’t work in mobile safari and chrome. the reason i mention it in here is that when i created a new project using the re-frame leiningen template, i didn’t encounter this problem. so i guess there must be something different about how luminus does things, and that creates weird issues with this one obscure use case.

feihong02:02:20

i’ve made some attempts to isolate the problem, but i’m pretty new to clojure(script) and i couldn’t figure it out

yogthos03:02:56

thanks for the heads up, would you happen to have a sample project to look at?

feihong05:02:02

this is just the starter project with a few changes to home-page function and a handler for :say-something event

yogthos05:02:58

thanks, I'll take a look tomorrow

yogthos20:02:53

@feihong.hsu I'm actually seeing the same behavior with the re-frame template locally here's the sample project I made from the re-frame template https://github.com/yogthos/re-frame-mobile-test

yogthos20:02:12

also as a side note it's better to use reg-event-fx for side effectful events:

(rf/reg-fx
 :speak
 (fn [_]
   (js/alert "test")
   (.speak js/speechSynthesis
           (js/SpeechSynthesisUtterance. "This won't come out on mobile"))))

(rf/reg-event-fx
 :say-something
 (fn [_ _]
   {:speak true}))
more info on how these work can be found here https://github.com/Day8/re-frame/blob/master/docs/EffectfulHandlers.md

yogthos20:02:00

it might be worth asking on the re-frame channel regarding this behavior, I can't see anything obvious that should be causing this either

yogthos20:02:13

this also seems to be specific to ios, I tried chrome on android and things work as expected

yogthos20:02:36

as I recall chrome on ios has to use safari engine, so that's likely why it's exhibiting the same behavior

yogthos20:02:02

what's interesting is that I added alerts around the speech call:

(rf/reg-fx
 :speak
 (fn [_]
   (js/alert "before speaking")
   (.speak js/speechSynthesis
           (js/SpeechSynthesisUtterance. "This won't come out on mobile"))
   (js/alert "after speaking")))

yogthos20:02:11

and I'm seeing both alerts pop up on ios

yogthos20:02:25

so it's definitely getting into the function, and running the code inside it

feihong20:02:09

@yogthos that’s weird, i wasn’t able to reproduce the problem using the re-frame template, but i will check out your sample project

feihong20:02:08

regarding the alerts you put in, yes, that’s consistent with what i’m seeing and what the behavior is supposed to be on mobile browsers

feihong20:02:35

the call to speechSynthesis.speak() won’t error out, it just won’t actually speak. the most common workaround is to have a button click handler that fires only once and invokes speechSynthesis.speak(“”), which “warms up” the API. subsequent calls to .speak() will then work even if they don’t come from a button click callback.

yogthos21:02:15

yeah I was thinking that could be a workaround, feels very hacky though 🙂

yogthos21:02:06

oh you know what

yogthos21:02:13

it looks like async dispatch is the problem

yogthos21:02:34

when I do

[:button.btn.btn-danger {:on-click #(rf/dispatch-sync [:say-something])}
                           "Speak using dispatch"]
that works as expected on safari

yogthos21:02:36

@feihong.hsu let me know if that does the trick in your case

feihong23:02:34

@yogthos yes, dispatch-sync totally works! so no hack needed now:smile: