简体   繁体   English

Blazor InputFile 重置/清除值 - statehaschanged() 不工作

[英]Blazor InputFile reset/clear value - statehaschanged() not working

I have a component using an Blazor InputFile component as a sub-component.我有一个使用 Blazor InputFile 组件作为子组件的组件。

When I select a file the OnChange handler is called as expected.当我选择一个文件时,将按预期调用 OnChange 处理程序。 However, if I select the same file twice the OnChange handler is not called again (which I guess is as intended since the selection did not change, however my use case needs this).但是,如果我两次选择同一个文件,则不会再次调用 OnChange 处理程序(我猜这是预期的,因为选择没有改变,但是我的用例需要这个)。

So, I figure if I can select a file and get a call to the OnChange handler and in the OnChange handler "reset" the selected file, then I should get a new call to the handler even if the same file is selected again.因此,我想如果我可以选择一个文件并调用 OnChange 处理程序并在 OnChange 处理程序中“重置”所选文件,那么即使再次选择同一个文件,我也应该对处理程序进行新调用。

I cant figure out how to reset the file selection in InputFile (sub)component.我不知道如何重置 InputFile(子)组件中的文件选择。 Calling this.StateHasChanged() in the handler doesn't cause the InputFile component to re-render.在处理程序中调用this.StateHasChanged()不会导致 InputFile 组件重新呈现。

Is this possible to do without JSInterop and manually setting the value-field of the DOM input element to "" (would that even work)?如果没有 JSInterop 并手动将 DOM 输入元素的值字段设置为“”(甚至可以工作),这是否可能?

My component:我的组件:

@using stuff;

<div class="drag-drop-area">
    Drag and drop file here
    <InputFile OnChange="@OnInputFileChange"></InputFile>
</div>

@code {

    [Parameter]
    public String SomeParam { get; set; } = "";

    private async Task OnInputFileChange(InputFileChangeEventArgs e) {
        // do stuff with file

        // do _something_ here to reset InputFile

        this.StateHasChanged(); //<-- this doesn't cause InputFile re-render
    }

My attempts to do this so far includes:到目前为止,我为此所做的尝试包括:

  • Following various tips/tricks related to this.遵循与此相关的各种提示/技巧。 StateHasChanged(), ie StateHasChanged(),即
    • await Task.Delay(1);
    • await InvokeAsync(StateHasChanged);
  • Adding values to InputFile using AdditionalAttributes.Add(..) to see if that could force a re-render使用AdditionalAttributes.Add(..)将值添加到 InputFile 以查看是否可以强制重新渲染
  • Looked at dynamically adding the InputFile component using RenderFragment, but I cant pass the OnChanged param (handler) when creating a new instance of InputFile in code, which means I wont the a callback with InputFileChangeEventArgs查看使用 RenderFragment 动态添加 InputFile 组件,但在代码中创建 InputFile 的新实例时我无法传递 OnChanged 参数(处理程序),这意味着我不会使用 InputFileChangeEventArgs 进行回调
  • Looked at wrapping the InputFile in a EditForm to reset the form (Blazor EditForms apparently doesnt have reset functionality?)查看将 InputFile 包装在 EditForm 中以重置表单(Blazor EditForms 显然没有重置功能?)
  • [EDIT] Used both Task and void for OnInputFileChange [编辑] 对 OnInputFileChange 同时使用 Task 和 void

Still not a very nice solution - but a bit more concise and it works:仍然不是一个很好的解决方案 - 但更简洁一些并且它有效:

Wrap the InputFile inside a boolean to temporarily hide/show.将 InputFile 包裹在 boolean 中以暂时隐藏/显示。 This clears the value.这将清除该值。

  @if (!bClearInputFile)
   {
       <InputFile class="form-control-file" OnChange="@OnInputFileChange" />
   }

   @code
   {
        //Call ClearInputFile whenever value must be cleared.
        private void ClearInputFile()
        {
            bClearInputFile = true;
            StateHasChanged();
            bClearInputFile = false;
            StateHasChanged();
        }
   }

Instead of calling StateHasChanged twice you can add a @key to the InputFile and change that when processing the OnChange event:您可以将 @key 添加到 InputFile 并在处理 OnChange 事件时更改它,而不是调用两次 StateHasChanged:

<InputFile @key=@(_inputFileId) OnChange="@LoadFiles" multiple />

@code {
    private string _inputFileId = Guid.NewGuid().ToString();
    
    private Task LoadFiles(InputFileChangeEventArgs e)
    {
        // load file here

        // the InputFile maintains the file the user has chosen and will ignore importing same file, i.e. you can't import the same file more than once to the inputfile control
        // to fix this the InputFile component key is changed so that blazor sees it as a new component and re-creates it in the browser DOM thereby clearing its state (and the file property of it)
        _inputFileId = Guid.NewGuid().ToString();

        return Task.CompletedTask;
    }

}```

Try using a conditional statement and render identical content under both conditions.尝试使用条件语句并在两种条件下呈现相同的内容。 Changing the conditional should force an update.更改条件应强制更新。

@if (@reviewMechanism == "IMPORT")
{
    <div>
        <u>Import</u>
        <br />
        <br />
        <div>

            <div class="btn  btn-sm" style="background-color: lightgray; margin-bottom: 5px; width: 250px; margin-left: 0px ">
                <span>
                    <button class="btn  btn-sm" style=" font: smaller; border: solid; border-color: gray; border-width: thin;  background-color: rgba(239, 239, 239, 1.00);  margin-left: 0px"
                            @onclick="DownloadTemplate">
                        Download
                    </button>
                    ReviewTemplate.csv
                </span>
            </div>
            <br />
            <div class="btn  btn-sm" style="font: smaller;  margin-bottom: 5px;  width: 250px ; background-color: lightgray;height: 40px">
                <InputFile OnChange="@LoadFiles" style=" margin-left: 10px"> Pick a File </InputFile>
            </div>
        </div>


    </div>
}
else if (@reviewMechanism == "IMPORT2")
{
    <div>
        <u>Import</u>
        <br />
        <br />
        <div>

            <div class="btn  btn-sm" style="background-color: lightgray; margin-bottom: 5px; width: 250px; margin-left: 0px ">
                <span>
                    <button class="btn  btn-sm" style=" font: smaller; border: solid; border-color: gray; border-width: thin;  background-color: rgba(239, 239, 239, 1.00);  margin-left: 0px"
                            @onclick="DownloadTemplate">
                        Download
                    </button>
                    ReviewTemplate.csv
                </span>
            </div>
            <br />
            <div class="btn  btn-sm" style="font: smaller;  margin-bottom: 5px;  width: 250px ; background-color: lightgray;height: 40px">
                <InputFile OnChange="@LoadFiles" style=" margin-left: 10px"> Pick a File </InputFile>
            </div>
        </div>


    </div>
}

When change desired:当需要改变时:

    loadedFiles = new Dictionary<IBrowserFile, string>();


    if (reviewMechanism == "IMPORT")
    {
        reviewMechanism = "IMPORT2"; //force render
    }
    else
    {
        if (reviewMechanism == "IMPORT2") reviewMechanism = "IMPORT"; //force render
    }

A little late to the party but I ran into a similar problem as the the OP with a slightly different use case.聚会有点晚了,但我遇到了与 OP 类似的问题,但用例略有不同。 But either way the solution seems to be straight forward and would probably work.但无论哪种方式,解决方案似乎都是直截了当的,并且可能会奏效。 Just use some old fashioned javascript.只需使用一些老式的 javascript。 So to reset the input element in the OnChange method, it would look like this:所以要重置OnChange方法中的输入元素,它看起来像这样:

    [Inject]
    private IJSRuntime _js { get; set; }
    private async Task OnInputFileChange(InputFileChangeEventArgs e)
    {
        IBrowserFile file = e.File;
        if (!ValidateFile(file))
        {
            //clearInput is the name of the javascript function
            //ref-upload is the id given to the InputFile element
            await _js.InvokeVoidAsync("clearInput", "ref-upload");
            return;
        }

    }

Then drop the following javascript function somewhere on your site like site.js :然后将以下 javascript function 放在您网站上的某处,例如site.js

function clearInput(inputId) {
    setTimeout(function () {
        var input = document.querySelector("#" + inputId);
        if (input) {
            input.value = "";
        }
    }, 30);
}

Below is common and easy solution.以下是常见且简单的解决方案。 Razor Component剃须刀组件

<InputFile @key=@(inputFileId) disabled="@DisabledUpload" OnChange="@OnInputFileChange"/>

Added @key添加了@key

Code section代码段

public Guid inputFileId = Guid.NewGuid();

// Once upload success in OnInputFileChange, Change id so that blazor re-renders InputFile as new component // 一旦在 OnInputFileChange 中上传成功,更改 id 以便 blazor 将 InputFile 重新呈现为新组件

inputFileId = Guid.NewGuid();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM