1

Just trying to get a preview thumbnail image to render with onDrop(). Something I have seen on several websites where you drop a document and it shows a thumbnail of the first page. I am either getting a broken link image, or no image at all.

This is what I am using as a reference, although not finding the official documentation too helpful:

https://react-dropzone.js.org/

React-Dropzone image preview not showing

https://medium.com/technoetics/handling-file-upload-in-reactjs-b9b95068f6b

And here is the code I am currently using. This doesn't render a thumbnail, but the Submit and Cancel buttons shift down like something is there, but I don't see anything.

import _ from 'lodash';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { submitDocument } from '../../actions/documents';
import Dropzone from 'react-dropzone';

class SubmitDocuments extends Component {

    constructor() {
        super();
        this.state = {
            filesToBeSent: [],
            filesPreview: [],
        }

        this.handleClick = this.handleClick.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
        this.onDrop = this.onDrop.bind(this);
    }

    handleClick(event) {
        this.setState({
            filesToBeSent: [],
            filesPreview: [],
        });
    }

    handleSubmit(event) {
        event.preventDefault();
        this.props.submitDocument(this.state.filesToBeSent);
    }

    onDrop(acceptedFiles) {
        console.log(acceptedFiles);
        var filesToBeSent = this.state.filesToBeSent;       
        _.map(acceptedFiles, f => {
            filesToBeSent.unshift(f);
        });

        filesToBeSent = _.uniqBy(filesToBeSent, 'name');

        var filesPreview = [];

        _.map(filesToBeSent, i => {
            filesPreview.unshift(
                <div key={i.name}>
                    {/*<h5>{i.name} - {i.size} bytes</h5>*/}
                    <img src={window.URL.revokeObjectURL(i.preview)} />
                </div>
            )            
        });

        this.setState({
            filesToBeSent,
            filesPreview
        });
    }

    render() {
        return (
            <form onSubmit={this.handleSubmit}>
                <div className='panel panel-default'>
                    <div className='panel-heading'>
                        <h4><strong>Submit Documents</strong></h4>
                    </div>

                    <div className='panel-body'>
                        <Dropzone className='dropzone' onDrop={this.onDrop}> 
                            <h3>Click to add files or drag files here to upload</h3>
                        </Dropzone>
                        {this.state.filesPreview}
                        <button type='submit' disabled={this.state.filesPreview.length < 1} className='btn btn-primary'>Submit</button>
                        <button type='button' className='btn btn-danger' onClick={this.handleClick}>Cancel</button>
                    </div>
                </div>
            </form>
        ); 
    }
}

function mapStateToProps(state) {
    return {
        survey_id: state.documents.survey_id
    }
}

export default connect(mapStateToProps, { submitDocument })(SubmitDocuments);

Now changing to the following results in the broken image icon:

<img src={i.preview} />

Things are uploading fine though.

What am I doing wrong here? I feel like my interpretation of preview might be different from what the documentation means, or that it only applies to image files, whereas mine should apply to .pdf, .xlsx., .txt.

EDIT

This is what the console.log(filesToBeSent) looks like.

filesToBeSent

This is what i looks like after lodash _.map(filesToBeSent, i => {}.

i after map

cjones
  • 8,384
  • 17
  • 81
  • 175

3 Answers3

0

That's because the data is returned as base64 encoded string and not a "url" of where its locally stored. Use this

<img alt="Embedded Image" src={`data:image/png;base64,${i.preview}`} />

Note that I've made the src equal to data:image/png;base64, (you must include the comma)

Joshua Underwood
  • 919
  • 4
  • 14
  • Thanks for the feedback. It now is generating a `net::ERR_INVALID_URL` error. The URL for `i.preview` does have the format: `blob:http://localhost:8000/a85a4fa8-2cf5-4c84-b939-c7609a4b9811`. Looking into resolving that issue. – cjones Jan 10 '18 at 20:18
  • Oh sorry. I don't actually use 'preview' with drop zone. I just use what you call `filesToBeSent` which should actually be the data string. In your case its an array but just provide the index. – Joshua Underwood Jan 10 '18 at 20:20
  • It sounds like I should just be referring to `i` then and it should be: `{}`. This however, results in the same error. I modified my question to show screenshots of what I am seeing. `i` would just refer to the index in `filesToBeSent` (but I could be wrong). – cjones Jan 10 '18 at 20:49
  • Well from your screenshots the first one is undefined...the second one shows you trying to pass an entire object to as the src note that it says `data:image/png;base64,[object File]` – Joshua Underwood Jan 10 '18 at 20:52
  • You could make an XMLHTTPRequest (or fetch) to the URL in preview and set the response type to blob to get back but that's just silly. I've used React Dropzone before but I always used it in conjunction with file reader. – Joshua Underwood Jan 10 '18 at 20:55
  • `handleChange = ( event ) => { const reader = new FileReader(); const file = event.target.files[0]; reader.onloadend = ( upload ) => { const images = [ ...this.state.images ].concat( upload.target.result ); this.setState({ images }); }; reader.readAsDataURL(file); };` This is the change handler I use on an `` – Joshua Underwood Jan 10 '18 at 20:57
  • Ok, those errors are confusing. I was mostly trying to demonstrate what is in the file objects and should have been more clear. The `[object File]` error is for: `{}` which should be the equivalent of `filesToBeSent[i]`. – cjones Jan 10 '18 at 20:58
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/162933/discussion-between-joshua-underwood-and-sockpuppet). – Joshua Underwood Jan 10 '18 at 20:58
  • Now just getting a `Failed to execute 'readAsDataURL' on 'FileReader': parameter 1 is not of type 'Blob'` when using `FileReader()`. – cjones Jan 11 '18 at 18:40
  • And you’re passing the preview right...not the whole object? Should be passing i.preview not i – Joshua Underwood Jan 11 '18 at 18:50
0

Turns out I would need something like this service to do what I am trying to accomplish:

FilePreviews.io

cjones
  • 8,384
  • 17
  • 81
  • 175
0

to be honest the better way is you generate it to your app , specially if you think about hybrid apps. you can do this on mac this way.

qlmanage -ti ../wherever/this/is/my_file.ext  -io wherever/you/want

this will just generate a thumb 20Ko 128x128 , if you want something bigger , you can specify the size. You can just get help on

qlmanage -h 
demopix
  • 159
  • 6