Inputs and now on the iPhone

Here’s a very simple interactive tool that displays the selection from a list of Radio buttons (from Observable inputs) together with the output of Date.now():

This works fine on my brand new Macbook (in Firefox, Chrome, and Safari) but the buttons are unresponsive in Safari on my iPhone. It makes a bit of sense to me that a browser with a slower implementation of Javascript might not run this so smoothly so I’m not certain if this is a bug or an error in my code. Either way, I do wonder if there’s a work around.

dang yeah i see it too, and i don’t see anything wrong with your code.

you don’t even need the Date.now() in there, it breaks (on iphone) if it’s just yield [n]. but not if it’s yield n!! weird!

will look into it! (gotta do some other stuff but i wanna try (1) if it breaks with the downloaded notebook bundle and (2) if it breaks with any generic html input)

1 Like

I would think so. In fact, I’ve been building animations and discovered the problem in that context. I discovered the example in my post after ripping out as much stuff as I could while still preserving the problem.

Thanks! At least I can go to sleep now. :slight_smile:

When you yield too fast (more than once in a second), on iOS at least, form elements, like checkbox or radios, can become unresponsive. I experienced the problem on my latest notebook where animating would cause the other controls (checkboxes and radios) to become unresponsive on iOS. I solved it just now: Rounding polygon corners / Mathieu Jouhet / Observable (see the code for the slider() function at the end).

I’m using Jeremy Ashkenas inputs that I customized long ago, but tested the same issue with the Observable inputs

What I was doing is I was basically yielding super fast an animated value and used it as the value for some of the parameters, controllable with a slider.

While I don’t know technically why this happens – it’s probably related to generators behavior on iOS, I inspected the scrubber @mbostock made which did not trigger a cell re-render when the value updated: Scrubber / Mike Bostock / Observable

I understood that if you use requestAnimationFrame to update the value instead of yielding it, you can get the controls to work again, I was pretty relieved. Until we find a better solution, I won’t use generator yielded animation values anymore, but instead values computed as a function of the current time (using new Date().getTime()) within a requestAnimationFrame loop.

Note that fast cell re-renders themselves don’t make the controls unresponsive, as demonstrated in the current version of my notebook, it’s only if you’re yielding very fast, which I’m not anymore since I’m using returns and re-rendering the cell as fast as the animated parameters update.

So what I did is I updated the slider input factory function to get additional props: animates and animateValue, the first one being a boolean to trigger the animation, and the second one being a function that receives the current time and returns the value at this point of time. I’m using sin functions but you can use different systems like Mike’s keyframes on his scrubber.

I also added a useAnimatedValueOnInit prop that indicates whether or not it should use the animated value as the current value when not animating, the alternative being using the input original value prop.

I used Mike’s very convenient disposal function to cleanup on cell invalidation.

I don’t know how you can transpose this to your way of doing things, but I hope it will help, it sure did for the animations on my end!

3 Likes

Indeed, when I increase the delay to 1000, it works; even 500 seems to do the job. Thanks!

Of course, I put the delay in there in the first place to experiment with this very issue; it just didn’t occur to me that the delay value would need to be so large.

@tophtucker Does this all make sense to you?

Yeah that delay quite bothered me :slight_smile:
Couldn’t resort to either stop the animations by default or make them happen at < 2 frames / sec just for the sake of getting the controls to work on iOS.

I guess my point is: for the time being, if you can think of a way to create your dynamic values at the very moment you need them, instead of yielding them in a generator cell, you should be fine with your controls AND get the ability to update your values at 60fps.

Sounds like a problem with the Inspector. Does the unresponsiveness persist if you yield a single html element (e.g. an empty div)? Also, does the unresponsiveness extend to page scrolling?

Page scrolling seems unaffected in all cases. And yeah, good call on the Inspector.

yield html`<div></div>` // fine
yield md`${n}` // fine
yield n // fine
yield [n] // broken (can't select input)
yield {n} // broken (can't select input)

So it seems like just the Inspector for objects (including arrays) that breaks. And I just tried downloading the notebook and running it on my phone (outside of Observable, just on a local web server) and it worked fine in all cases!! So it seems we’ve narrowed the problem down nicely, thank you! Filed a bug, stay tuned…

1 Like

@tophtucker Do you notice the problem in embeds as well?