# \[elm/file\] Selecting files using File.Select.file(s) "sometimes" fails

**URL:** <https://discourse.elm-lang.org/t/elm-file-selecting-files-using-file-select-file-s-sometimes-fails/2701>\
**Category:** Request Feedback\
**Created:** [December 5, 2018, 10:46am UTC](https://discourse.elm-lang.org/t/elm-file-selecting-files-using-file-select-file-s-sometimes-fails/2701 "2018-12-05T10:46:18Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![ymtszw](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/ymtszw/32/2360_2.png) [@ymtszw](https://discourse.elm-lang.org/u/ymtszw)\
**Post date:** [December 5, 2018, 10:46am UTC](https://discourse.elm-lang.org/t/elm-file-selecting-files-using-file-select-file-s-sometimes-fails/2701/1 "2018-12-05T10:46:18Z")

</div>

## Update

The issue described in this post is most likely resolved by patch release [elm/file 1.0.2](https://github.com/elm/file/commit/f51218a17afd83cf984e64060f4415d092372f57)!

Related:

- [Cross-browser compatibility fix for File.Select.file(s) in elm/file](https://discourse.elm-lang.org/t/cross-browser-compatibility-fix-for-file-select-file-s-in-elm-file/3060)
- [https://github.com/elm/file/issues/4](https://github.com/elm/file/issues/4)

Thank you everyone! ❤

* * *

This is seemingly a known, but not-definitely-resolved? problem.  
Reference: [javascript - Event onChange won’t trigger after files are selected from code-generated INPUT element - Stack Overflow](https://stackoverflow.com/questions/39399947/event-onchange-wont-trigger-after-files-are-selected-from-code-generated-input)

## Background

`File.Select.file` and `File.Select.files` do the following ([source](https://github.com/elm/file/blob/1.0.1/src/Elm/Kernel/File.js#L82)):

1. Generate a `input[type="file"]` element behind the scene (not rendered)
2. Set `change` event handler on the element, handling a new file selection
3. Dispatch an artificial `click` event to the element, triggering file selector window

This works, and is actually a method well-known even [MDN documentation has it](https://developer.mozilla.org/en-US/docs/Web/API/File/Using_files_from_web_applications#Using_hidden_file_input_elements_using_the_click()_method) (so-called “hidden file input” trick).  
As the linked MDN page says, this trick is employed for replacing “ugly” browser-default file input element with your own styled buttons/elements.

(And as the elm/file documentation states, for security reasons, the above listed sequences must be executed directly upon some user inputs (like actual clicks). Though this restriction is already considered and properly handled by kernel codes, so at least in my experience, it’s working reliably)

Here’s working example ([Ellie](https://ellie-app.com/45g4bZJGKtma1)):

```elm
module Main exposing (main)

import Browser
import File exposing (File)
import File.Select
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onClick)

type alias Model =
    { file : Maybe File }

init : () -> ( Model, Cmd Msg )
init () =
    ( { file = Nothing }, Cmd.none )

type Msg
    = ReqFile
    | GotFile File

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        ReqFile ->
            ( model, File.Select.file ["*/*"] GotFile )

        GotFile f ->
            ( { model | file = Just f }, Cmd.none )

view : Model -> Html Msg
view model =
    div []
        [button [ onClick ReqFile] [text "File Select"]
        , div []
            [ text <|
                case model.file of
                    Just f ->
                        File.name f ++ " (" ++ File.mime f ++ ")"

                    Nothing ->
                        "(empty)"
            ]
        ]

main : Program () Model Msg
main =
    Browser.element
        { init = init
        , view = view
        , update = update
        , subscriptions = always Sub.none
        }

```

## Symptom

Again, it works, but **not reliably**. In a small example like the one above, it should almost always work. But when this pattern of codes are introduced in real projects, it **“sometimes”** fails.

The actual symptom is that after you selected a file (or files) and hit OK in the file selector window, **`change` event is “sometimes” not fired (OR, fired but not caught), thus not registering the file selection!**  
I encountered this on Chrome (both Windows 10 and mac), Safari. But NOT in Firefox (mac).

By quoting **“sometimes”** I emphasize this behavior happens very unpredictably. My gut feeling tells in larger and busier apps that run many event handling other than file selections, this happens more, even to the level of “almost never works”. To support this, my app has `Time.every` ticks for triggering background polling tasks, in that app I see the problem very often. But while disabling `Time.every` ticks, the problem almost ceases to happen (but still happens occasionally.)

Since I myself have not thoroughly investigated conditions for reproduction, I am a bit hesitant to open an issue, but after some searching I found that this was actually a known issue around this “hidden file input” trick. That is the link I put at the top of the issue.  
[javascript - Event onChange won’t trigger after files are selected from code-generated INPUT element - Stack Overflow](https://stackoverflow.com/questions/39399947/event-onchange-wont-trigger-after-files-are-selected-from-code-generated-input)  
Also there is another one: [javascript - input[type=file] change event are lost occasionally on Chrome - Stack Overflow](https://stackoverflow.com/questions/38845015/inputtype-file-change-event-are-lost-occasionally-on-chrome)  
The situation described in these SO posts are basically equivalent to my case with `File.Select.file` although both are 2-year-old threads.

Speculations by posters includes:

- race condition around call stack
- node is gone (perhaps GCed?) before file selection
- issue around registering event handler (node is gone BEFORE handler is registered?), this I doubt though

I actually managed to reproduce the behavior **just once** on Ellie with the example app above, but not consistently after that. At successful(?) reproduction, I searched around directories in file selector window for several minutes with occasional waits in between (taking time can contribute?).

## ToDos/Requests

- Since I do not have concrete condition to reproduce the problem, I want to hear from folks who happen to have seen similar symptoms.
- Also, if you have reliable workaround for this issue (preferably using `File.Select.file` OR other means to use styled file input trigger element.)
- Hints for narrowing down the problem, since I do have a project and test data that can reliably reproduce the symptom, I can try your suggestions.
  - Actually, the code is available [here](https://github.com/ymtszw/zephyr/commit/6896f93439d532cd6071f7da518e8fe7732fafaf) (linking to related commit) but not yet advertised openly

Thank you for your attention!

---

<div class="post-metadata">

**Author:** ![klaftertief](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/klaftertief/32/5338_2.png) [@klaftertief](https://discourse.elm-lang.org/u/klaftertief)\
**Post date:** [December 5, 2018, 11:00am UTC](https://discourse.elm-lang.org/t/elm-file-selecting-files-using-file-select-file-s-sometimes-fails/2701/2 "2018-12-05T11:00:52Z")

</div>

We are in the process of switching to new new file and http packages for file uploads. I have not played around with `File.Select.file` yet, we’ll see how it work. We currently have a `label` element, rendered as a button, that is linked to a hidden file input via `for` and `id` attributes. This allows for custom styling. We then decode the file on file input change manually. Maybe this is workaround for you as well?

---

<div class="post-metadata">

**Author:** ![ymtszw](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/ymtszw/32/2360_2.png) [@ymtszw](https://discourse.elm-lang.org/u/ymtszw)\
**Post date:** [December 5, 2018, 11:16am UTC](https://discourse.elm-lang.org/t/elm-file-selecting-files-using-file-select-file-s-sometimes-fails/2701/3 "2018-12-05T11:16:34Z")

</div>

> [@klaftertief](#):
>
> We currently have a `label` element, rendered as a button, that is linked to a hidden file input via `for` and `id` attributes.

That was actually a next thing I wanted to try, since it is also [mentioned in MDN](https://developer.mozilla.org/en-US/docs/Web/API/File/Using_files_from_web_applications#Using_a_label_element_to_trigger_a_hidden_file_input_element).  
My concern is that whether the workaround is compatible with elm-ui. Will find out.

---

<div class="post-metadata">

**Author:** ![kyasu1](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/kyasu1/32/126_2.png) [@kyasu1](https://discourse.elm-lang.org/u/kyasu1)\
**Post date:** [December 5, 2018, 2:49pm UTC](https://discourse.elm-lang.org/t/elm-file-selecting-files-using-file-select-file-s-sometimes-fails/2701/4 "2018-12-05T14:49:28Z")

</div>

I have been experiencing same issue so far.

Here is my testing code taken from my project which uploads multiple files by selecting individual file. You can try it on Ellie and experience the problem if you are lucky enough 😛 It should be reproduced better on local environment (elm repl) with Chrome.

[https://ellie-app.com/45mGKjBvbMJa1](https://ellie-app.com/45mGKjBvbMJa1)

My observations are

- This happen on Chrome like once in ten times without using Time.every. And interestingly most time, the third or fourth upload attempt fails. Sometimes not happen at all.
- I could observe it happen on Ellie with Chrome, though the possiblity is relatively low like once in hundred times.
- On Safari, I could notice the failure but the occurrence rate was lower than Chrome.
- On Firefox, I have not experienced this failure though not tested much…
- Tested on Mac OS X only with latest browsers.

This may be not Elm issue but pretty annoying ☹

---

<div class="post-metadata">

**Author:** ![evancz](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/evancz/32/16_2.png) [@evancz](https://discourse.elm-lang.org/u/evancz)\
**Post date:** [December 5, 2018, 5:51pm UTC](https://discourse.elm-lang.org/t/elm-file-selecting-files-using-file-select-file-s-sometimes-fails/2701/5 "2018-12-05T17:51:32Z")

</div>

I have seen this as well, but I wasn’t sure what was going on.

The current approach creates an `<input>` node but does not put it into the DOM. You can see how it works [here](https://github.com/elm/file/blob/master/src/Elm/Kernel/File.js#L82-L112). The idea was that it’d get garbage collected later at some point, but maybe that is where the problem is.

Can someone test this with just JS code to see:

1. If the bug reproduces with the exact same JS and no Elm code.
2. If so, does adding it to the DOM and then removing it in the event handler make it more reliable?

I do not really like (2) because I do not want to mess with the DOM and potentially disrupt virtual-dom. The click should be synchronous, so it may work alright. Not super confident in that approach without testing it out a bunch.

---

<div class="post-metadata">

**Author:** ![ymtszw](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/ymtszw/32/2360_2.png) [@ymtszw](https://discourse.elm-lang.org/u/ymtszw)\
**Post date:** [December 6, 2018, 1:49pm UTC](https://discourse.elm-lang.org/t/elm-file-selecting-files-using-file-select-file-s-sometimes-fails/2701/6 "2018-12-06T13:49:49Z")

</div>

Glad there are at least multiple cases this is observed! Now it became a clearly known issue.

For now my workaround is reducing main thread work load by suppressing recurring tasks via turning off `Time.every` while file selector is open. Even in my rather large SPA, this can greatly increase reliability of file selection.

Using `<label>` and visually-hidden file input could work, but after a few attempt, I found it cumbersome to do that with elm-ui. It is definitely possible with `Element.html` and `Html.label`, however we need to “manually” style non-elm-ui part , and carefully keep it inline with other elm-ui-controlled parts.

> [@evancz](#):
>
> If so, does adding it to the DOM and then removing it in the event handler make it more reliable?

My first thoought was node getting GCed before callback is called, so yes, adding it to the DOM until it is actually “used” may remedy the situation. But my concern is, if the file selector is cancelled or the same file is selected (the case known for not firing new `change` event), there seems to be no good chance of removing the node from the DOM. In that case zombie input node can remain in the DOM. Will try that if I got a time, though.

---

<div class="post-metadata">

**Author:** ![kyasu1](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/kyasu1/32/126_2.png) [@kyasu1](https://discourse.elm-lang.org/u/kyasu1)\
**Post date:** [December 6, 2018, 3:37pm UTC](https://discourse.elm-lang.org/t/elm-file-selecting-files-using-file-select-file-s-sometimes-fails/2701/7 "2018-12-06T15:37:33Z")

</div>

Maybe it is illogical way and contrived method but I think I found a condition that cause this issue almost all time under Chrome on Mac OS X.

The following code is based on the `elm/file` as mentioned by @evancz .

```auto
<!doctype html>
<html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <button onClick="upload()">Upload</button>
        <script>
            let counter = 0;
            function upload() {
              var node = document.createElementNS('http://www.w3.org/1999/xhtml', 'input');
              node.setAttribute('type', 'file');
              node.setAttribute('accept', ['image/*']);
              node.addEventListener('change', function(event) {
                cb(event.target.files[0]);
              });
              node.dispatchEvent(new MouseEvent('click'));
              // if comment out the following line I could not observe the failure
              // console.log(node)
            }
            function cb(file) {
              console.log(`${++counter} : ${file.name}`)
            }
        </script>
    </body>
</html>

```

1. When the code was opened from Chrome as a local file, the issue was also confirmed.
2. Interesting thing is, if you resize the window size while opening the selection dialog box, the file selection fail almost all time. In Chrome on Mac OS X, you can resize the window by double clicking outside of the dialog box.
3. But if uncomment the `console.log(node)` below `dispatchEvent`, the file selection do not fail.
4. All of the above results also apply to the JavaScript code compiled by Elm.

I am not expert so I can not see what is going on under the hood, but hope this may help.

---

<div class="post-metadata">

**Author:** ![choonkeat](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/choonkeat/32/1555_2.png) [@choonkeat](https://discourse.elm-lang.org/u/choonkeat)\
**Post date:** [December 9, 2018, 7:59am UTC](https://discourse.elm-lang.org/t/elm-file-selecting-files-using-file-select-file-s-sometimes-fails/2701/8 "2018-12-09T07:59:32Z")

</div>

Does seem like a GC issue. I suspect `console.log` interferes because the browser console UI retains a reference to it for you to inspect.

You may not like this solution, but it keeps `node` in scope and fixes the symptoms

```
 function _File_uploadOne(mimes)
 {
+ var node
        return _Scheduler_binding(function(callback)
        {
- var node = document.createElementNS('http://www.w3.org/1999/xhtml', 'input');
+ node = document.createElementNS('http://www.w3.org/1999/xhtml', 'input');
                node.setAttribute('type', 'file');

```

It keeps 1x `node` around but mitigates the “cancel” scenario (the next click overwrites this `node` variable and hopefully the old value GCs then…)

_CORRECTION: actually the `node` should be outside even `_File_uploadOne` so no matter how many uploads were setup, there’s only 1x dangling `node`_

> Can someone test this with just JS code to see

Here’s a minimal version with 1 edit that fixes it [Revisions · node-onchange.html · GitHub](https://gist.github.com/choonkeat/f0439ca5b95518cd142613224da5e100/revisions)

NOTE: my tests were all on Chrome

---

<div class="post-metadata">

**Author:** ![system](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/1X/50a05e53677a2c3b47776d7abd0f113eb50193a1.png) [@system](https://discourse.elm-lang.org/u/system)\
**Post date:** [December 19, 2018, 7:59am UTC](https://discourse.elm-lang.org/t/elm-file-selecting-files-using-file-select-file-s-sometimes-fails/2701/9 "2018-12-19T07:59:42Z")

</div>

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.
