'Changing an Input value in Blazor by javascript doesn't change it's binded property value
I'm building a website using app.net core 3.1 with blazor.
In one of my components I have :
<input @bind="Message" type="text" id="input-message"/>
Message is just a string property.
and I have javascript:
document.getElementById('input-message').value = 'some text';
The problem is after running the above js, <input> value changes but Message value doesn't, and of course if I type or paste something inside <input> , Message value changes too.
Solution 1:[1]
You shouldn't change the input value directly in javascript, what you should do is call a c# function that updates the value and then it will update the javascript.
Instead of doing
document.getElementById('input-message').value = 'some text';
You should do something like
DotNet.invokeMethodAsync('UpdateMessageValue', 'some text');
Where you have
public void UpdateMessageValue(string value){
Message = value;
}
And because you are using bind in the input, the value of document.getElementById('input-message').value will be changed, and the value in the c# will also be changed.
This answer isn't complete, I'm passing you the idea on how to do it and not the correct code to solve your case, but if you want more information on how to do it, you can take a look at Call .NET methods from JavaScript functions in ASP.NET Core Blazor.
Solution 2:[2]
If you don't have control over the third-party lib script that is modifying your input field you can always use the following solution.
The concept is the following:
After rendering the component we call JS to start intercepting the all input fields value setters, then we get our callback in Blazor from JS. Blazor then dispatches to appropriate field.
Fields example:
<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:
Inside OnAfterRenderAsync call InitInputFieldsToTrackOnce on first rendering (or second one in case of server with prerendering):
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);
}
And dispose _objRef when disposing your component.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 |
