-
-
Notifications
You must be signed in to change notification settings - Fork 328
-
Hi, this package is so cool.
I'm trying to use an input to get an image from the client into bytes (or anything I can open with PIL on the server side). I've tried to use the Input widget with type='file', and the resulting argument to the callback is a fakepath. I can also see that value is the only key in the event dictionary with the same fakepath when I create a handler manually and use idol.html.input. From my limited js knowledge, the fakepath is not useful and a bytes array from event['target']['result'] is what I was hoping for.
@events.on("change") def on_change(event: Dict[str, Any]) -> None: value = event['target']['result'] update_image_bytes(value) return idom.html.input( { 'id': 'image-input', 'type': 'file', 'hidden': True, 'accept': 'image/*' }, event_handlers=events )
I also think that I could do it if I could access the input like document.getElementById("#image-input").files[0], but I don't know anything about that in idom. I guess that another possibility would be to use a js component here.
To be clear, I don't really want to post/upload, I'm basically just trying to display the file after being b64 encoded and used as src in an image element (I have been able to get this encoding and displaying working in js). Any help would be greatly appreciated.
Beta Was this translation helpful? Give feedback.
All reactions
I've created an issue to track this: #375
Replies: 1 comment 7 replies
-
I've created an issue to track this: #375
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 1
-
I'm on main so maybe there's a difference, but I'm actually getting a files key, it's just not serializing correctly. The following code:
import idom @idom.component def Test(): return idom.html.input({"type": "file", "id": "my-input", "onChange": print}) idom.run(Test, port=8000)
Produces the following output when a file is added:
{'value': 'C:\\fakepath\\some-file.txt', 'files': {'0': {}}}
Beta Was this translation helpful? Give feedback.
All reactions
-
@ksmoore17 I think the reason you're not seeing the latest updates is due to a bug in how the JS build dir is updated. You should get the same output as me if you run idom restore. This will be fixed in the next release.
Beta Was this translation helpful? Give feedback.
All reactions
-
Seeing that files key now! And with a dict representation of the file object. Realizing now that I will need to use the js FileReader api or something similar (File.arrayBuffer()) since the python side can't really work with the files from the "handles" (the dicts returned in the files key). I tried for a bit to return it in those dicts in the hasFiles callback (tacking it on as a string). This was the general idea:
files: Array.from(target.files).map((file) => { var bytes; file.arrayBuffer().then((buffer) => {bytes = buffer}); return { lastModified: file.lastModified, name: file.name, size: file.size, type: file.type, bytes: bytes } })
This seems like a dead end because it's an async process, and it was supposed to be a hack anyway. I think it would be nice to have a python idom.util function or something like a useFile hook that can take this file handle that is being successfully sent to the python event handler and access the FileReader api on the browser to send back the bytes array. Let me know what you think, I would be interested in working on this.
Beta Was this translation helpful? Give feedback.
All reactions
-
I think this might be best written as a custom component, the API for which has been subject to change in the past. However I think it'll be mostly finalized in the next release so once it's out I can make the necessary changes and remove the warning from the template repository.
Beta Was this translation helpful? Give feedback.
All reactions
-
I can imagine the JS module might look like this:
export function createElement() {}; export function renderElement() {}; export function unmountElement() {}; export function FileInput({ onChange }) { const handleChange = (event) => { const fileDataPromises = Array.from(event.target.files).map(promiseFileData); Promise.all(fileDataPromises).then((files) => onChange({ files: files }); }; return <input onChange={handleChange} /> } function promiseFileData(file) { return file.arrayBuffer().then((bytes) => ( { lastModified: file.lastModified, name: file.name, size: file.size, type: file.type, bytes: bytes } )) }
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 1