0

I want to create a component in Blazor to allow users to upload a file with drag & drop or paste the image in their clipboard.

I saw a couple of posts:

In the first post the author creates a Razor page

@* file: DropZone.razor *@
@inject IJSRuntime JSRuntime
@implements IAsyncDisposable

<h1>Upload files!</h1>

<div @ref="dropZoneElement" class="drop-zone">
    <p>Drop a file or paste an image from the clipboard or select a file using the input</p>
    <InputFile OnChange="@OnChange" @ref="inputFile" />
</div>

@* Display the uploaded image *@
<img src="@src" />

@code {
    ElementReference dropZoneElement;
    InputFile inputFile;

    IJSObjectReference _module;
    IJSObjectReference _dropZoneInstance;

    string src;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            // Load the JS file
            _module = await JSRuntime.InvokeAsync<IJSObjectReference>("import", "./dropZone.js");

            // Initialize the drop zone
            _dropZoneInstance = await _module.InvokeAsync<IJSObjectReference>("initializeFileDropZone", 
                                      dropZoneElement, inputFile.Element);
        }
    }

    // Called when a new file is uploaded
    async Task OnChange(InputFileChangeEventArgs e)
    {
        using var stream = e.File.OpenReadStream();
        using var ms = new MemoryStream();
        await stream.CopyToAsync(ms);
        src = "data:" + e.File.ContentType + ";base64," + Convert.ToBase64String(ms.ToArray());
    }

    // Unregister the drop zone events
    public async ValueTask DisposeAsync()
    {
        if (_dropZoneInstance != null)
        {
            await _dropZoneInstance.InvokeVoidAsync("dispose");
            await _dropZoneInstance.DisposeAsync();
        }

        if (_module != null)
        {
            await _module.DisposeAsync();
        }
    }
}

and a javascript file to use in the page

// file: wwwroot/dropZone.js
export function initializeFileDropZone(dropZoneElement, inputFile) {
    // Add a class when the user drags a file over the drop zone
    function onDragHover(e) {
        e.preventDefault();
        dropZoneElement.classList.add("hover");
    }

    function onDragLeave(e) {
        e.preventDefault();
        dropZoneElement.classList.remove("hover");
    }

    // Handle the paste and drop events
    function onDrop(e) {
        e.preventDefault();
        dropZoneElement.classList.remove("hover");

        // Set the files property of the input element and raise the change event
        inputFile.files = e.dataTransfer.files;
        const event = new Event('change', { bubbles: true });
        inputFile.dispatchEvent(event);
    }

    function onPaste(e) {
        // Set the files property of the input element and raise the change event
        inputFile.files = e.clipboardData.files;
        const event = new Event('change', { bubbles: true });
        inputFile.dispatchEvent(event);
    }

    // Register all events
    dropZoneElement.addEventListener("dragenter", onDragHover);
    dropZoneElement.addEventListener("dragover", onDragHover);
    dropZoneElement.addEventListener("dragleave", onDragLeave);
    dropZoneElement.addEventListener("drop", onDrop);
    dropZoneElement.addEventListener('paste', onPaste);

    // The returned object allows to unregister the events when the Blazor component is destroyed
    return {
        dispose: () => {
            dropZoneElement.removeEventListener('dragenter', onDragHover);
            dropZoneElement.removeEventListener('dragover', onDragHover);
            dropZoneElement.removeEventListener('dragleave', onDragLeave);
            dropZoneElement.removeEventListener("drop", onDrop);
            dropZoneElement.removeEventListener('paste', handler);
        }
    }
}

Although the post is quire recent, it doesn't work. First, because in this line

_dropZoneInstance = await _module.InvokeAsync<IJSObjectReference>
                          ("initializeFileDropZone", dropZoneElement, inputFile.Element);

inputFile doesn't have a property Element. Then, the javascript has export but it is not recognized.

How is it possible to create a similar component without using a third-part component?

Enrico
  • 3,592
  • 6
  • 45
  • 102
  • Even though it says BlazorInputFile is obsolete, I think it has just morphed into InputFile. The following post might give you some clues how to customize InputFile component: https://stackoverflow.com/a/65241311/10787774 – Jason D Nov 05 '21 at 15:41
  • you should use java script to access client memory for paste act. – AliNajafZadeh Nov 06 '21 at 10:11

0 Answers0