3

I'm making a "fluid" textarea, which resizes it's height according to it's content. I'm actually trying to implement this script. I have the following code: https://ellie-app.com/Vjtvm6yrKWa1/4

The issue is that when increasing, it works with no problem, but when trying to decrease height, it doesn't work as expected.

How to reproduce the issue:

  1. The textarea comes with a default text. If you click on the textarea, it will resize it's height to the content.
  2. Delete half of the text or the entire text.
  3. Click in the textarea again. The expected behaivor is that it should resize it's height again,recuding it's height, but it doesn't. It does either nothing or reduces the height just a little (making you have to click a lot of times until the height is ok)

I think it's something related to the virual-dom preventing the scrollHeight to change, something like a cache (performance-wise), but it's only a guess.

What could be my problem?

Ps. When trying to use other kind of events, like "input" or "change", this issue also occurs.

Community
  • 1
  • 1
Mateus Felipe
  • 1,071
  • 2
  • 19
  • 43

2 Answers2

3

EDIT 4/20: ilias on the Slack channel linked to this: https://ellie-app.com/H5x9DC4J9ba1/0 (Ellie of pure Elm autoexpannding text area)

=====

I doubt it's an issue w/ decoders.

Notice that in the JS example when textarea content changes 2 things are done to get the new height:

-- set textarea..height to auto
-- get textarea..scrollHeight.

Without first setting to auto the JS example, too, exhibits the behavior you're seeing in the Elm example.

Now notice the sequence of events in the Elm example:

1-- remove some lines of text
2-- click the textarea; this calculates current height (before setting height to auto)
3-- ... then dispatches HeightChange
4-- ... which dispatches AutoHeight, then UpdateHeight with the old height from step 2

Thus, again, I doubt it's an issue w/ a decoder. To check, see the following (quick/dirty) Ellie -- it toggles height between auto and a calculated height, and you'll see that the correct height is calculated every other click: https://ellie-app.com/WwBDfDvhypa1/0

(Aside: Elm may coalesce values queued for the same animation frame, dunno w/o looking at source, but that's still beside the point here.)

pakx
  • 236
  • 1
  • 6
  • This is exactly what I though could be happening. But does Elm provide any way to do what I'm willing? How would you implement, in Elm, the attached script? Is there a way to force a message *before* receiving the `scrollOffset` value? – Mateus Felipe Apr 17 '17 at 09:34
  • 1
    As yet I don't see a way to do that w/o native code. It's tempting to think that in an `on "input"...` we could first call `update AutoHeight model` in a let, then (somehow) rig things to set the calculated height in `TextChange`, but unsurprisingly model mutations performed outside `update` disappear for not being the model managed by the runtime :) Until better informed I'd investigate packaging that "fluid textarea" as a webcomponent. See https://github.com/rtfeldman/elm-google-maps and surrounding discussion. – pakx Apr 18 '17 at 19:17
  • Maybe this is the only solution by now. I'm going to wait to see what they say about the issue I've opened. – Mateus Felipe Apr 18 '17 at 19:29
  • Would you post a link to this github issue you raised? – pakx Apr 18 '17 at 20:20
  • Read it, thx. Thing is ... IMO this is neither inconsistent nor unexpected behavior, so I'm curious what response the github issue elicits. (What you're trying to achieve -- i.e. set a property immediately before reading another -- is still useful, but different from the "issue" raised.) – pakx Apr 18 '17 at 20:40
  • I agree with you. Actually, when I opened the issue, I was not completely aware of what the problem could be. Maybe I could edit it to make it clearer, and wait for what would they say. It's worthy to remember that Elm is at 0.18. Maybe they already have something in mind to solve this kind of problem. – Mateus Felipe Apr 19 '17 at 06:59
  • I gave the bounty to you as it seems I won't have any conclusive answer to this until the time is over, and you mantained a discussion about the issue with me. – Mateus Felipe Apr 20 '17 at 14:01
  • Thx, but honestly it's undeserved -- all I did was point out that the issue wasn't an issue. Besides, being new to SO, I don't yet care about its reward system:) All that said, perhaps post a new question asking how to handle your specific case, w/o native code, of needing to update a property immediately before reading another one? – pakx Apr 20 '17 at 14:20
  • People in Stack Overflow are not as "advanced" as other old languages. I don't think they are going to be of help, as if this was the case, I think someone would answer this one correctly which was not the case, even with a bounty. I think it's a problem the Elm team itself may handle, I'm going to wait they to answer (they are slow a lot, haha) – Mateus Felipe Apr 20 '17 at 15:13
  • Take this for what it's worth, `Just` my opinion :-p : I won't embarrass 'em by naming names, but IMO some people on this channel know their sh#t (perhaps for carryover experience in ML languages) *and* are meticulous in their responses. In fact part of my education is to read all their responses I can find. – pakx Apr 20 '17 at 15:45
1

I've checked out the code, and indeed the problem seems to be with the scrollHeight decoder. On every click - it decreases the value by just 2 px. Ex: 424, 422, 420.. and so on. Not the real value.

I don't know why, can't find any docs regarding this issue - but you can provide almost the same functionality using keypress event. This is the function you need:

whenBackspacePressed_ReceiveScrollHeight : (Int -> msg) -> Attribute msg
whenBackspacePressed_ReceiveScrollHeight tagger =
  let
     isBackspace code =
        if code == 8 then
            Decode.succeed "Backspace pressed"
        else
            Decode.fail "is not Backspace - is this error shown anywhere?!"

    decode_Backspace =
        Decode.andThen isBackspace Html.Events.keyCode
  in
    Html.Events.on "keypress" (Decode.map2 (\key scrollHeightValue-> tagger scrollHeightValue) decode_Backspace targetHeight)

Map2 is used here to ensure that both isBackspace and the targetHeight are decoded successfully at once.

And add this event in the view :

Html.textarea 
    [ style model
    , onClick HeightChange
    , whenBackspacePressed_ReceiveScrollHeight HeightChange
    , onInput TextChange, .. etc

It works when keeping backspace pressed. But is not instantaneous in the way you want, check it out here: ellie.app ..

AIon
  • 12,521
  • 10
  • 47
  • 73
  • Thanks for your answer. Unfortunately, that's not what I need. I think it's not actually about what we are doing, but something on the internals. I opened an [issue](https://github.com/elm-lang/html/issues/127) in GitHub about it, but no one has answered yet. – Mateus Felipe Apr 15 '17 at 22:17