Reset input field value if value is invalid in Blazor
Asked Answered
I

2

0

I have some text fields binding inside a for loop.

<Input type="text" @onchange='(ChangeEventArgs e)=>DataChange(e,item)' value="@item.value" />

here if user type anything to the input fields I have a custom validation inside DataChange function.

private void DataChange(ChangeEventArgs e, PnL pnl)
  {
    if(e.Value.ToString().Contains(10))
     {
       pnl.value = e.Value.ToString();
     }
  }

if change is valid then only Iam assigning value to the item in the list. But if its invalid i need to reset the value to original.

I have tried calling StateHasChange() but that didn't helps. Can anybody helps?

Iconology answered 24/8, 2021 at 4:48 Comment(2)
Do you really want to reset a TextBox while the user is typing? They might not like that.Wimer
the function fires once the focus of element loses. thats working fine by using onchanges event.Iconology
B
4

Try this:

private async Task DataChange(ChangeEventArgs e, PnL pnl)
  {
    if(e.Value.ToString().Contains(10))
     {
       pnl.value = e.Value.ToString();
     }
else
  {
    var tempValue = pnl.value;
    pnl.value = string.Empty();
    await Task.Yield();
    pnl.value = tempValue;
  }
 }

So what happens here is this.

  1. The code runs synchronously to the await Task.Yield.
  2. At this point pnl.value is a blank string.
  3. DataChange yields execution to the Blazor event handler which loads a render action onto the Renderer Queue.
  4. The Yield allows the Renderer to service it's render queue, and re-render the component. pnl.value is blank - different from the last render - so the input gets updated in the DOM.
  5. The code after the yield now runs to completion, setting pnl.value back to it's original value.
  6. DataChange completes and the Blazor event handler loads a second render action onto the Renderer Queue which now re-renders the input as the value has changed again.

In your code everything runs synchronously. You can call StateHasChanged as many times as you like, the Renderer only gets task time to run it's queue after DataChange completes. At this point the Renderer still thinks the input is set to the original value of pnl.value (not the edited value), so the DOM doesn't get updated.

There's an article on CodeProject with more detail - https://www.codeproject.com/Articles/5310624/Blazor-UI-Events-and-Rendering

Burnette answered 24/8, 2021 at 10:18 Comment(2)
so here Task.Yield() fakes a asynchronous process right?Iconology
Yes and no. With Yield (or Task.Wait) it is asynchronous. In a Blazor Event everything happens on the Synchronization Context thread. Calling StateHasChanged queues a RenderFragment on the Renderer Queue, but that's all. If the SC Thread is blocked by the Event Code, the Renderer can't service it's queue. You Yield or Task.Delay() to let that happen.Burnette
F
1

When the @onchange is happening, the binding is already over, so the invalid string is at that time in pnl.value.

One of the solution could be an extra property for binding. The value property would only change when the tempVal is valid, otherwise it would reset the tempVal:

<input type="text" @bind-value="item.tempVal" />

@code {
    PnL item = new() { value = "hello10hi", tempVal = "hello10hi" };//valid values
    class PnL
    {
        public string value { get; set; }
        string _tempVal;
        public string tempVal { get => _tempVal; set { _tempVal = value; DataChange(value, this); } }

        void DataChange(string newVal, PnL pnl)
        {
            if (newVal.Contains("10"))//is valid
            {
                pnl.value = newVal;
            }
            else
            {
                pnl.tempVal = pnl.value;
            }
        }
    }

}

EDIT (The code has been updated).

The problem was, that the tempVal was not updating when writing, so it still had the default value, so no change after assigning the value, thus no update in UI.

With bind-value the tempVal will be always updated. The "problem" there is that we loose the onechange code (because we use bind). Thus I had to interact with changes inside the tempVal property.

Fellini answered 24/8, 2021 at 8:1 Comment(1)
For some reason it works when you unfocus with valid value and then insert the invalid one... give me a while.Fellini

© 2022 - 2024 — McMap. All rights reserved.