{"action":"created","issue":{"url":"https://api.github.com/repos/VeliovGroup/Meteor-Files/issues/182","repository_url":"https://api.github.com/repos/VeliovGroup/Meteor-Files","labels_url":"https://api.github.com/repos/VeliovGroup/Meteor-Files/issues/182/labels{/name}","comments_url":"https://api.github.com/repos/VeliovGroup/Meteor-Files/issues/182/comments","events_url":"https://api.github.com/repos/VeliovGroup/Meteor-Files/issues/182/events","html_url":"https://github.com/VeliovGroup/Meteor-Files/issues/182","id":170490503,"number":182,"title":"Do you have sample code for Meteor with React?","user":{"login":"maitrid","id":4511745,"avatar_url":"https://avatars.githubusercontent.com/u/4511745?v=3","gravatar_id":"","url":"https://api.github.com/users/maitrid","html_url":"https://github.com/maitrid","followers_url":"https://api.github.com/users/maitrid/followers","following_url":"https://api.github.com/users/maitrid/following{/other_user}","gists_url":"https://api.github.com/users/maitrid/gists{/gist_id}","starred_url":"https://api.github.com/users/maitrid/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/maitrid/subscriptions","organizations_url":"https://api.github.com/users/maitrid/orgs","repos_url":"https://api.github.com/users/maitrid/repos","events_url":"https://api.github.com/users/maitrid/events{/privacy}","received_events_url":"https://api.github.com/users/maitrid/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/VeliovGroup/Meteor-Files/labels/Documentation","name":"Documentation","color":"000000"},{"url":"https://api.github.com/repos/VeliovGroup/Meteor-Files/labels/help%20wanted","name":"help wanted","color":"bfdadc"}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":7,"created_at":"2016-08-10T18:50:10Z","updated_at":"2016-08-17T02:21:05Z","closed_at":null,"body":"Any code showing the use in Meteor 1.3 with React, jsx files?"},"comment":{"url":"https://api.github.com/repos/VeliovGroup/Meteor-Files/issues/comments/240296002","html_url":"https://github.com/VeliovGroup/Meteor-Files/issues/182#issuecomment-240296002","issue_url":"https://api.github.com/repos/VeliovGroup/Meteor-Files/issues/182","id":240296002,"user":{"login":"vtocco","id":10001398,"avatar_url":"https://avatars.githubusercontent.com/u/10001398?v=3","gravatar_id":"","url":"https://api.github.com/users/vtocco","html_url":"https://github.com/vtocco","followers_url":"https://api.github.com/users/vtocco/followers","following_url":"https://api.github.com/users/vtocco/following{/other_user}","gists_url":"https://api.github.com/users/vtocco/gists{/gist_id}","starred_url":"https://api.github.com/users/vtocco/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vtocco/subscriptions","organizations_url":"https://api.github.com/users/vtocco/orgs","repos_url":"https://api.github.com/users/vtocco/repos","events_url":"https://api.github.com/users/vtocco/events{/privacy}","received_events_url":"https://api.github.com/users/vtocco/received_events","type":"User","site_admin":false},"created_at":"2016-08-17T02:21:05Z","updated_at":"2016-08-17T02:21:05Z","body":"Here is my react components (two of them, put the individual file in a separate file to make it cleaner). One is for the upload portion and one displays each file. I have methods for renaming and deleting on the server where you should do lots of validation.. Also has a progress bar for uploading. \r\n\r\nI wasn't able to get this to work with the web workers enabled, but I saw some recent work in that area so it might be fixed, so set that to true if you need it. \r\n\r\nThis is using the older mixin method for meteor data.  I also added console logs so you can put different things in the node events and see whats going on.\r\n\r\nThanks for the awesome work btw! \r\n\r\n\r\n```\r\nimport React from 'react';\r\nimport {Meteor} from 'meteor/meteor';\r\nimport IndividualFile from './FIleIndividualFile.jsx';\r\nimport {_} from 'meteor/underscore';\r\n\r\nconst FileUploadComponent = React.createClass({\r\n    mixins: [ReactMeteorData],\r\n\r\n    getInitialState(){\r\n        return {\r\n            uploading: [],\r\n            progress: 0,\r\n            inProgress: false\r\n        }\r\n    },\r\n\r\n    getMeteorData() {\r\n        var handle = Meteor.subscribe('files.all');\r\n        return {\r\n            docsReadyYet: handle.ready(),\r\n            docs: UserFiles.find().fetch()\r\n        };\r\n    },\r\n\r\n    uploadIt(e){\r\n        \"use strict\";\r\n        e.preventDefault();\r\n\r\n        let self = this;\r\n\r\n        if (e.currentTarget.files && e.currentTarget.files[0]) {\r\n            // We upload only one file, in case\r\n            // there was multiple files selected\r\n            var file = e.currentTarget.files[0];\r\n\r\n            if (file) {\r\n                let uploadInstance = UserFiles.insert({\r\n                    file: file,\r\n                    meta: {\r\n                        locator: self.props.fileLocator,\r\n                        userId: Meteor.userId()\r\n                    },\r\n                    streams: 'dynamic',\r\n                    chunkSize: 'dynamic',\r\n                    allowWebWorkers: false\r\n                }, false);\r\n\r\n                self.setState({\r\n                    uploading: uploadInstance,\r\n                    inProgress: true\r\n                });\r\n\r\n                uploadInstance.on('start', function () {\r\n                    console.log('Starting');\r\n                });\r\n\r\n                uploadInstance.on('end', function (error, fileObj) {\r\n                    console.log('On end File Object: ', fileObj);\r\n                });\r\n\r\n                uploadInstance.on('uploaded', function (error, fileObj) {\r\n                    console.log('uploaded: ', fileObj);\r\n\r\n                   //remove the filename from the upload box\r\n                    self.refs['fileinput'].value = '';\r\n\r\n                    self.setState({\r\n                        uploading: [],\r\n                        progress: 0,\r\n                        inProgress: false\r\n                    });\r\n                });\r\n\r\n                uploadInstance.on('error', function (error, fileObj) {\r\n                    console.log('Error during upload: ' + error);\r\n                });\r\n\r\n                uploadInstance.on('progress', function (progress, fileObj) {\r\n                    console.log('Upload Percentage: ' + progress);\r\n                    self.setState({\r\n                        progress: progress\r\n                    })\r\n                });\r\n\r\n                uploadInstance.start();\r\n            }\r\n        }\r\n    },\r\n\r\n    showUploads() {\r\n\r\n        console.log('**********************************', this.state.uploading);\r\n\r\n        if (!_.isEmpty(this.state.uploading)) {\r\n\r\n            return <div>\r\n                {this.state.uploading.file.name}\r\n                <div className=\"progress progress-bar-default\">\r\n                    <div style={{width: this.state.progress + '%'}} aria-valuemax=\"100\"\r\n                         aria-valuemin=\"0\"\r\n                         aria-valuenow={this.state.progress || 0} role=\"progressbar\"\r\n                         className=\"progress-bar\">\r\n                        <span className=\"sr-only\">{this.state.progress}% Complete (success)</span>\r\n                        <span>{this.state.progress}%</span>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        }\r\n    },\r\n\r\n\r\n    render() {\r\n\r\n        if (this.data.docsReadyYet) {\r\n            'use strict';\r\n\r\n            let fileCursors = this.data.docs;\r\n\r\n            let showit = fileCursors.map((aFile, key) => {\r\n                // console.log('A file: ', aFile.link(), aFile.get('name'));\r\n\r\n                let link = UserFiles.findOne({_id: aFile._id}).link();\r\n\r\n                return <div key={'file' + key}>\r\n                    <IndividualFile\r\n                        fileName={aFile.name}\r\n                        fileUrl={link}\r\n                        fileId={aFile._id}\r\n                        fileSize={aFile.size}\r\n                    />\r\n                </div>\r\n            });\r\n\r\n            return <div>\r\n                <div className=\"row\">\r\n                    <div className=\"col-md-12\">\r\n                        <p>Upload New File:</p>\r\n                        <input type=\"file\" id=\"fileinput\" disabled={this.state.inProgress} ref=\"fileinput\"\r\n                               onChange={this.uploadIt}/>\r\n                    </div>\r\n                </div>\r\n\r\n                <div className=\"row m-t-sm m-b-sm\">\r\n                    <div className=\"col-md-6\">\r\n\r\n                        {this.showUploads()}\r\n\r\n                    </div>\r\n                    <div className=\"col-md-6\">\r\n                    </div>\r\n                </div>\r\n\r\n                {showit}\r\n\r\n            </div>\r\n        }\r\n        else return <div></div>\r\n    }\r\n});\r\n\r\n\r\nconst IndividualFile = React.createClass({\r\n\r\n    propTypes: {\r\n        fileName: React.PropTypes.string.isRequired,\r\n        fileSize: React.PropTypes.number.isRequired,\r\n        fileUrl: React.PropTypes.string,\r\n        fileId: React.PropTypes.string.isRequired\r\n    },\r\n\r\n\r\n    removeFile(){\r\n        \"use strict\";\r\n        let conf = confirm('Are you sure you want to delete the file?') || false;\r\n        if (conf == true) {\r\n            Meteor.call('RemoveFile', this.props.fileId, function (err, res) {\r\n                if (err)\r\n                    console.log(err);\r\n            });\r\n        }\r\n    },\r\n\r\n\r\n    renameFile(){\r\n        \"use strict\";\r\n\r\n        let validName = /[^a-zA-Z0-9 \\.:\\+()\\-_%!&]/gi;\r\n\r\n        let prompt = window.prompt('New file name?', this.props.fileName);\r\n\r\n        //replace any non valid characters\r\n        if (prompt) {\r\n            prompt = prompt.replace(validName, '-');\r\n            prompt.trim();\r\n        }\r\n\r\n        if (!_.isEmpty(prompt)) {\r\n            Meteor.call('RenameFile', this.props.fileId, prompt, function (err, res) {\r\n                if (err)\r\n                    console.log(err);\r\n            });\r\n        }\r\n    },\r\n\r\n    render() {\r\n\r\n        return <div className=\"m-t-sm\">\r\n\r\n            <div className=\"row\">\r\n                <div className=\"col-md-12\">\r\n                    <strong>{this.props.fileName}</strong>\r\n                    <div className=\"m-b-sm\">\r\n                    </div>\r\n                </div>\r\n\r\n            </div>\r\n\r\n            <div className=\"row\">\r\n                <div className=\"col-md-3\">\r\n                    <button onClick={this.renameFile} className=\"btn btn-outline btn-primary btn-sm\">\r\n                        Rename\r\n                    </button>\r\n                </div>\r\n\r\n\r\n                <div className=\"col-md-3\">\r\n                    <a href={this.props.fileUrl} className=\"btn btn-outline btn-primary btn-sm\"\r\n                       target=\"_blank\">View</a>\r\n                </div>\r\n\r\n                <div className=\"col-md-2\">\r\n                    <button onClick={this.removeFile} className=\"btn btn-outline btn-danger btn-sm\">\r\n                        Delete\r\n                    </button>\r\n                </div>\r\n\r\n                <div className=\"col-md-4\">\r\n                    Size: {this.props.fileSize}\r\n                </div>\r\n            </div>\r\n        </div>\r\n    }\r\n});\r\n\r\nexport default FileUploadComponent;\r\n```"}}
{"actor":{"display_login":"vtocco"}}