通过 JavaScript 更改 Blazor 中的输入值不会更改其绑定的属性值



我正在使用app.net core 3.1blazor构建一个网站。在我的一个组件中,我有:

<input @bind="Message" type="text" id="input-message"/>

Message只是一个字符串属性。

我有javascript:

document.getElementById('input-message').value = 'some text';

问题是在运行上面的js之后,<input>的值会改变,但Message的值不会改变,当然,如果我在<input>中键入或粘贴一些东西,Message的值也会改变。

显然,通过javascript更改<input>值或DOM中的任何其他更改都不会更改State,因此blazor不会重新渲染组件。即使在剃须刀页面中手动调用StateHasChanged();也不起作用。

要做到这一点,您只需要触发与用户正常修改<input>时相同的DOM事件,如下所示:

var myElement = document.getElementById('input-message');
myElement.value = 'some text';
var event = new Event('change');
myElement.dispatchEvent(event);

您不应该直接在javascript中更改输入值,您应该调用一个c函数来更新值,然后它会更新javascript。

而不是做

document.getElementById('input-message').value = 'some text';

你应该做一些类似的事情

DotNet.invokeMethodAsync('UpdateMessageValue', 'some text');

在哪里

public void UpdateMessageValue(string value){
Message = value;
}

因为您在输入中使用bind,所以document.getElementById('input-message').value的值将更改,c#中的值也将更改。

这个答案还不完整,我向您传递的是如何做到这一点的想法,而不是解决您的问题的正确代码,但如果您想了解更多关于如何做到的信息,您可以查看ASP.NET Core Blazor中JavaScript函数的Call.NET方法。

如果您无法控制正在修改输入字段的第三方lib脚本,则可以始终使用以下解决方案
概念如下:
渲染组件后,我们调用JS开始拦截所有输入字段的值设置器,然后我们从JS中获得Blazor中的回调。Blazor随后派遣到适当的场地。

字段示例:

<div class="input-group input-daterange" data-date-format="dd.mm.yyyy">
<input type="text" 
id="InputDateFrom" 
@bind="InputDateFrom" 
class="form-control text-center" placeholder="От">
<span class="input-group-addon"><i class="fa fa-angle-right"></i></span>
<input type="text" 
id="InputDateTo" 
@bind="InputDateTo" 
class="form-control text-center" placeholder="До">
</div>  

JS:

function WatchInputFields(callbackChangedName, dotnetRef) {
var descriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value");
var originalSet = descriptor.set;
// define our own setter
descriptor.set = function (val) {
console.log("Value set", this, val);
originalSet.apply(this, arguments);
dotnetRef.invokeMethodAsync(callbackChangedName, this.id, this.value);
}
Object.defineProperty(HTMLInputElement.prototype, "value", descriptor); }

BLAZOR:
OnAfterRenderAsync内部,在第一次渲染时调用InitInputFieldsToTrackOnce(如果服务器有预渲染,则调用第二次(:

private async Task InitInputFieldsToTrackOnce()
{
_objRef = DotNetObjectReference.Create(this);
await JS.InvokeVoidAsync(
"WatchInputFields",
"OnInputFieldChanged",
_objRef);
WatchInputField("InputDateFrom", (value) => { _InputDateFrom = value; Console.WriteLine($"Setting FROM to {value}"); });
WatchInputField("InputDateTo", (value) => { _InputDateTo = value; ; Console.WriteLine($"Setting TO to {value}"); });
}
void WatchInputField(string id, Action<string> onChanged)
{
InputFieldChanges.TryAdd(id, onChanged);
}

private ConcurrentDictionary<string, Action<string>> InputFieldChanges { get; } = new ConcurrentDictionary<string, Action<string>>();
private DotNetObjectReference<ShopDesk> _objRef;
[JSInvokable]
public async Task OnInputFieldChanged(string id, string value)
{
var ok = InputFieldChanges.TryGetValue(id, out Action<string> action);
if (ok)
action(value);
}

并在处理组件时处理_objRef

相关内容

  • 没有找到相关文章

最新更新