woutdp / live_svelte

Svelte inside Phoenix LiveView with seamless end-to-end reactivity
https://hexdocs.pm/live_svelte
MIT License
1.01k stars 38 forks source link

Example how to upload a file #76

Open gevera opened 10 months ago

gevera commented 10 months ago

Hey, @woutdp

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

Thanks

woutdp commented 10 months ago

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 commented 10 months ago

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 commented 10 months ago

Have you tried upload instead of uploadTo?

gevera commented 10 months ago

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 commented 10 months ago

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 commented 10 months ago

Just a silly check, but your constant is named handleImageUpload and your template on:change is set to {handleInput} as per the code you posted. You probably changed that already but you never know!

On Thu, Aug 31, 2023 at 2:04 PM Denis Donici @.***> wrote:

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

no live file inputs found matching the name "hub[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

app.js:36 app.js:44891 — Reply to this email directly, view it on GitHub , or unsubscribe . You are receiving this because you are subscribed to this thread.Message ID: ***@***.***>
gevera commented 10 months ago

handleImageUpload

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

woutdp commented 10 months ago

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 commented 9 months ago

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.