Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example how to upload a file #76

Open
gevera opened this issue Aug 31, 2023 · 9 comments
Open

Example how to upload a file #76

gevera opened this issue Aug 31, 2023 · 9 comments

Comments

@gevera
Copy link

gevera commented Aug 31, 2023

Hey, @woutdp

Is there an example how could I use Live Svelte to upload an image or a text file?

Thanks

@woutdp
Copy link
Owner

woutdp commented Aug 31, 2023

I don't have an example, but check out upload and uploadTo (https://hexdocs.pm/phoenix_live_view/js-interop.html#client-hooks-via-phx-hook)

These functions are available on the live prop, so you can do something like this:

<script>
    export let live
    live.upload(...)
    // or
    live.uploadTo(...)
</script>

That should point you in the right direction. I haven't tested it out though, but in theory it should work just fine, let me know if you get stuck/things don't work, I'd be happy to take a look at it. And if it works, feel free to add an example to the repo, or leave a comment so I can add yours :)

@gevera
Copy link
Author

gevera commented Aug 31, 2023

Hey, thanks for reply. Thats what I've actually tried to do like so

<script>
export let live;
// edited handleImageUpload 
const  handleInput = (e) => {
    live.uploadTo("image", [e.detail])
  }
</script>

<input
    type="file"
    name="image"
    id="image"
    on:change={handleInput}
    class="file-input cursor-pointer"
    accept="image/png, image/jpeg"
  />

And here is my server file

def mount(_params, _session, socket) do

    {:ok,
     socket
     |> allow_upload(:image, accept: ~w(.jpg .jpeg .png), max_entries: 1)
  end

And here is the errors I got in the browser console

nothing found matching the phx-target selector "image" undefined [utils.js:7:61](http://localhost:3333/deps/phoenix_live_view/assets/js/phoenix_live_view/utils.js)
  logError utils.js:7
  withinTargets view.js:233
  uploadTo view_hook.js:60
  handleImageUpload app.js:36841
  createEventDispatcher lifecycle.js:105
  createEventDispatcher lifecycle.js:104
  handleInput app.js:35651
  (Async: EventListener.handleEvent)
  listen dom.js:359
  listen_dev dev.js:133
  mount app.js:35546
  mount_component Component.js:44
  mount app.js:35886
  mount app.js:29303
  mount_component Component.js:44
  mount app.js:35816
  mount app.js:36683
  mount app.js:30034
  mount_component Component.js:44
  mount app.js:36776
  mount_component Component.js:44
  init Component.js:151
  Hubs app.js:36973
  mounted hooks.js:106
  __mounted view_hook.js:17
  maybeAddNewHook view.js:369
  performPatch view.js:379
  trackAfter dom_patch.js:65
  trackAfter dom_patch.js:65
  perform dom_patch.js:243
  perform dom_patch.js:243
  performPatch view.js:405
  applyJoinPatch view.js:331
  onJoinComplete view.js:308
  onJoin view.js:272
  applyDiff view.js:241
  onJoin view.js:256
  join view.js:636
  after live_socket.js:915
  requestDOMUpdate live_socket.js:271
  join view.js:636
  matchReceive push.js:76
  matchReceive push.js:76
  startTimeout push.js:107
  trigger channel.js:278
  Channel channel.js:70
  trigger channel.js:278
  onConnMessage socket.js:550
  decode serializer.js:25
  onConnMessage socket.js:537
  onmessage socket.js:235
  (Async: EventHandlerNonNull)
  connect socket.js:235
  doConnect live_socket.js:210
  connect live_socket.js:219
  <anonymous> app.js:36
  <anonymous> app.js:44850

@woutdp
Copy link
Owner

woutdp commented Aug 31, 2023

Have you tried upload instead of uploadTo?

@gevera
Copy link
Author

gevera commented Aug 31, 2023

Certainly. This is what I get with live.upload("image", [e.detail])

no live file inputs found matching the name "image" undefined utils.js:7:61
    logError utils.js:7
    dispatchUploads view.js:1040
    upload view_hook.js:56
    handleInput app.js:35668
    (Async: EventListener.handleEvent)
    listen dom.js:359
    listen_dev dev.js:133
    mount app.js:35571
    mount_component Component.js:44
    mount app.js:35923
    mount app.js:29335
    mount_component Component.js:44
    mount app.js:35849
    mount app.js:36724
    mount app.js:30066
    mount_component Component.js:44
    mount app.js:36817
    mount_component Component.js:44
    init Component.js:151
    Hubs app.js:37014
    mounted hooks.js:106
    __mounted view_hook.js:17
    maybeAddNewHook view.js:369
    performPatch view.js:379
    trackAfter dom_patch.js:65
    trackAfter dom_patch.js:65
    perform dom_patch.js:243
    perform dom_patch.js:243
    performPatch view.js:405
    applyJoinPatch view.js:331
    onJoinComplete view.js:308
    onJoin view.js:272
    applyDiff view.js:241
    onJoin view.js:256
    join view.js:636
    after live_socket.js:915
    requestDOMUpdate live_socket.js:271
    join view.js:636
    matchReceive push.js:76
    matchReceive push.js:76
    startTimeout push.js:107
    trigger channel.js:278
    Channel channel.js:70
    trigger channel.js:278
    onConnMessage socket.js:550
    decode serializer.js:25
    onConnMessage socket.js:537
    onmessage socket.js:235
    (Async: EventHandlerNonNull)
    connect socket.js:235
    doConnect live_socket.js:210
    connect live_socket.js:219
    <anonymous> app.js:36
    <anonymous> app.js:44891

@gevera
Copy link
Author

gevera commented Aug 31, 2023

It looks like the error is coming from view.js dispatchUploads function

dispatchUploads(name, filesOrBlobs){
    let inputs = DOM.findUploadInputs(this.el).filter(el => el.name === name)
    if(inputs.length === 0){ logError(`no live file inputs found matching the name "${name}"`) }
    else if(inputs.length > 1){ logError(`duplicate live file inputs found matching the name "${name}"`) }
    else { DOM.dispatchEvent(inputs[0], PHX_TRACK_UPLOADS, {detail: {files: filesOrBlobs}}) }
  }

As if live_view is not seeing the target element 🤔 https://github.com/phoenixframework/phoenix_live_view/blob/56697d304e7a2bba960e71c3ee3c4101af4fb769/assets/js/phoenix_live_view/dom.js#L51

@pcharbon70
Copy link

pcharbon70 commented Aug 31, 2023 via email

@gevera
Copy link
Author

gevera commented Aug 31, 2023

handleImageUpload

Yes, I did edit that. It was just a quick copy paste. Good catch 👁️

@woutdp
Copy link
Owner

woutdp commented Aug 31, 2023

It looks correct to me so not sure what's going on here. I'll invest some time in figuring it out and adding an example later on, I'll ping here once that's done, might take some time though as I'm working on other things at the moment.

@vonagam
Copy link
Contributor

vonagam commented Sep 9, 2023

Looking at the code it seems that upload and uploadTo are supposed to work with inputs rendered on server side with live_file_input and managed by Phoenix.LiveFileUpload hook on js side.

The error is pretty clear - there were no matching inputs. Here is code of findUploadInputs with straightforward selector where PHX_UPLOAD_REF is "data-phx-upload-ref".

Here is the code for live_file_input. So the challenge is to make matching markup and make sure that phoenix live js runs the LiveFileUpload hook. Seems like non-trivial thing to do. If slots can work with that then it is an easier path with passing a rendered file input through a slot. But if slots do not work (most likely there will be problems) and js is too hard then you can simply render those inputs as hidden outside of live svelte component, should do the trick.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants