Skip to content

How to display selected file name? #528

Open

Description

@iraszl

Without the bootstrap_form gem by default the rails forms show the filename or the number of files when selected, so the user knows they successfully selected a file to be uploaded in the form.
Screenshot 2019-03-26 at 12 01 02 PM

However, when I use bootstrap_form, the file name and count is gone. Is there a way to bring it back, otherwise the users think that they failed to select the file and try again, and sometimes give up thinking the file select in the form is broken.

Activity

  1. lcreid commented on Mar 27, 2019

    @lcreid
    Contributor

    Thanks for the feedback. I know that the file upload control is implemented in a different way than some of the other controls. I don't know why, as it was done before I was a maintainer. I'm sure there was a good reason. I will add this to my list of issues to look at.

    In the meantime, you can implement your own fields to give feedback. That's what I've done.

  2. iraszl commented on Mar 28, 2019

    @iraszl
    Author

    Thanks for the kind comment. What do you mean by your own fields? Do you have an example of what you've done please?

  3. lcreid commented on Mar 28, 2019

    @lcreid
    Contributor

    I have one example I can share:

    <%= bootstrap_form_with(model: @document, local: true) do |f| %>
      <div class="row">
        <div class="col-sm-6">
          <%= f.text_field(:uri, label: "File Name", disabled: true) %>
        </div>
        <div class="col-sm-6">
          <%= content_tag(:div, "&#8203;".html_safe, class: "mb-2 d-none d-sm-block") %>
          <%= f.file_field(:uri, hide_label: true, label: "URI") %>
        </div>
      </div>
      <div class="row">
        <div class="col">
          <%= link_to "Cancel", :back, class: "btn btn-primary" %>
        </div>
        <div class="col">
          <%= f.primary "Upload", class: "btn btn-primary float-right", disabled: true %>
        </div>
      </div>
    <% end %>
    

    The text field named uri (never mind why I called it that) actually is the file name of the file that was uploaded. If you were uploading the document with an AJAX request you'd have to add some JavaScript to the solution. In my case, it was simply doing a round trip to the server, so when the page re-rendered, the file name was shown.

    I don't have any examples where I was uploading multiple files and showing a count on the screen. Sorry.

    I hope this helps.

  4. iraszl commented on Mar 29, 2019

    @iraszl
    Author

    Thank you for being so helpful!

  5. codeandclay commented on Apr 15, 2019

    @codeandclay

    @iraszl Here's a naive way of showing the name of the file immediately after the file has been selected. No need for custom fields.

    // Workaround for displaying selected file
    $(document).on('ready turbolinks:load', function() {
      $('.custom-file-input').change(function(){
        $('.custom-file-label').text(this.value);
      });
    });

    This works for my file field:

    <%= bootstrap_form_for @listing do |form| %>
    ...
     <%= form.file_field :image, direct_upload: true, accept: "image/png,image/gif,image/jpeg", label: "Add an image" %>
    ...
    <% end %>

    Before file has been selected:
    Screenshot 2019-04-15 at 16 09 06

    After file has been selected:
    Screenshot 2019-04-15 at 16 35 46

  6. iraszl commented on Apr 15, 2019

    @iraszl
    Author

    @codeandclay Thank you so much! I'm going to test this out ASAP!

  7. hwhelchel commented on Apr 20, 2019

    @hwhelchel

    This is the recommended solution by the bootstrap folks

    import bsCustomFileInput from 'bs-custom-file-input';
    $(document).ready(function () {
      bsCustomFileInput.init();
    })
  8. hwhelchel commented on Apr 20, 2019

    @hwhelchel
  9. iraszl commented on Apr 20, 2019

    @iraszl
    Author

    @codeandclay Solution works.
    @hwhelchel Doesn't seem to work. Do I need to add some class to the form to make it work?

  10. lcreid commented on Apr 20, 2019

    @lcreid
    Contributor

    @iraszl If you're using Turbolinks (by default Rails does), perhaps @hwhelchel 's solution will work if you change the second line as follows:

    import bsCustomFileInput from 'bs-custom-file-input';
    $(document).on('ready turbolinks:load', function() {
      bsCustomFileInput.init();
    })

    You'll also have to make sure you include the package. Follow the link in this comment for instructions.

  11. lcreid commented on Apr 20, 2019

    @lcreid
    Contributor

    This is an elegant solution. At the moment, bootstrap_form doesn't ship any JavaScript. Do you think it's good enough to document this solution in the README, rather than change the code?

  12. iraszl commented on Apr 21, 2019

    @iraszl
    Author

    @lcreid Works great. But note that this line is not needed in the javascript if you load the library:
    import bsCustomFileInput from 'bs-custom-file-input';
    Can you confirm if I'm correct or not?

  13. added a commit that references this issue on Jun 28, 2019
  14. Halloran commented on Sep 21, 2019

    @Halloran

    FWIW, while this issue is open, you can solve the issue by sprinkling a bit of script into your form:

    <script type="application/javascript">
        $('input[type="file"]').change(function(e){
            var fileName = e.target.files[0].name;
            $('.custom-file-label').html(fileName);
        });
    </script>
    
  15. davidray commented on Sep 23, 2019

    @davidray

    If you have multiple file fields, you could do something like this so they all don't get updated to show the same value:

    $('.custom-file-input').change(function(e){
      var fileName = e.target.files[0].name;
      $(`.custom-file-label[for=${e.currentTarget['id']}]`).html(fileName);
    });
    
  16. Halloran commented on Sep 23, 2019

    @Halloran

    @davidray nice catch. Your solution works both when multiple: true and multiple: false Thanks

  17. barriault commented on Jan 22, 2020

    @barriault

    Here is the solution that worked for me on a Rails 6 app. A big thanks to @hwhelchel and @lcreid for their comments above. From the terminal run:

    yarn add bs-custom-file-input
    

    Add the following to your project's javascript/packs/application.js file:

    import bsCustomFileInput from 'bs-custom-file-input';
    $(document).on('ready turbolinks:load', function() {
      bsCustomFileInput.init();
    })

    Use one of these in your view:

    <%= f.file_field(:image) %>
    <%= f.file_field(:images, multiple: true, placeholder: "Choose files") %>
  18. anastaszi commented on Jul 8, 2020

    @anastaszi

    For novices like me and who work just with plain JS (in case you use turbolinks) [based on the solution by @codeandclay]:

    Add this function to app/assets/javascript/custom/[file_name].js:

    document.addEventListener('turbolinks:load', function() {
      var fileInput = document.querySelector('.custom-file-input');
      var fileLabel = document.querySelector('.custom-file-label');
      fileInput.addEventListener("change", (e) => {fileLabel.textContent = e.target.value.replace(/^.*[\\\/]/, ''); });
    }, false);

    And in your file_field you don't need to change a thing

    <%= bootstrap_form_for(@project, local: true) do |form| %>
        <%= form.file_field :attachments, label_class: "text-muted", label: "Add attachment"  %>
        <%= form.submit %>
    <% end %>

    After file was selected you'll see this:

    Screen Shot 2020-07-07 at 10 13 20 PM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions