Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blazor WebAssembly: make ChangeEventArgs.Value work both ways for the scope of the event handler #38520

Closed
noseratio opened this issue Nov 19, 2021 · 3 comments
Labels
area-blazor Includes: Blazor, Razor Components feature-rendering Features dealing with how blazor renders components

Comments

@noseratio
Copy link

noseratio commented Nov 19, 2021

Is your feature request related to a problem? Please describe.

I'd like to be able to undo invalid user input without changing the state of the component or using the bind:value Blazor data binding feature.

I'm trying to do that inside oninput event handler like below (online repl).

I've found that ChangeEventArgs.Value, while being a get/set property, only works one way, from JS to DotNet. More so, StateHasChanged doesn't trigger rerendering in this case. Thus, I had to resort to JS interop to revert the changes inside the <input> box A.

(To be clear, I realize this is a horrible hack; it could possible be improved by using ElementReference and an isolated JS import, but it all wouldn't be necessary if we could just do e.Value = count below).

<label>Count:</label>
<button @onclick=Increment>@count times!</button><br>
A: <input @oninput=OnChange value="@count" id="@id"><br>
B: <input @bind-value=count @bind-value:event="oninput">

@code {
    int count = 1;
    string id = Guid.NewGuid().ToString("N");

    void Increment() => count++;

    void OnChange(ChangeEventArgs e)
    {
        var userValue = e.Value?.ToString(); 
        if (int.TryParse(userValue, out var v))
        {
            count = v;
        }
        else 
        {
            if (String.IsNullOrWhiteSpace(userValue))
            {
                count = 0;
            }

            // this doesn't work
            e.Value = count.ToString();

            // this doesn't work either (no rererendering):
            StateHasChanged();           
       }
    }
}

Describe the solution you'd like

Make ChangeEventArgs.Value work both ways for the scope of the event handler. This would allow for custom input validation logic outside standard bind-xxx Blazor data binding attributes.

For example, I can do this in Svelte (which I find conceptually very close to Blazor):

<script>
  let count = 1;
  const handleClick = () => count++;
  const handleChange = e => {
    const userValue = e.target.value;
    let newValue = userValue? parseInt(userValue): 0;
    if (isNaN(newValue)) newValue = count;
    if (newValue === count)
      e.target.value = count; // undo user input
    else
      count = newValue;	
  };	
</script>

Count: <button on:click={handleClick}>{count}</button><br/>
A: <input value={count} on:input={handleChange}/><br/>

And here it is in React:

function App() {
  let [count, setCount] = useState(1);
  const handleClick = () => setCount((count) => count + 1);
  const handleChange = (e) => {
    const userValue = e.target.value;
    let newValue = userValue ? parseInt(userValue) : 0;
    if (isNaN(newValue)) newValue = count;
    // re-render even when count hasn't changed
    setCount(newValue); 
  };
  return (
    <>
      Count: <button onClick={handleClick}>{count}</button><br/>
      A: <input value={count} onInput={handleChange}/><br/>
    </>
  );
}

Additional context

https://stackoverflow.com/q/70016908/1768303

To clarify, I simply want to undo whatever I consider an invalid input, retrospectively after it has happened (by handling the change event), without mutating the component's state itself (counter here).

That is, without Blazor-specific two-way data binding, HTML native type=number or pattern matching attributes. I use the number format requirement here as an example; I want to be able to undo any arbitrary input like that.

I might be missing something, but I find this surprisingly difficult to do in Blazor, compared to other frameworks. I'd like to be able to use StateHasChanged to simply re-render the component in its current state.

@TanayParikh TanayParikh added area-blazor Includes: Blazor, Razor Components feature-blazor-form-validation This issue is related to forms validation in Blazor labels Nov 19, 2021
@javiercn javiercn added feature-rendering Features dealing with how blazor renders components and removed feature-blazor-form-validation This issue is related to forms validation in Blazor labels Nov 22, 2021
@javiercn javiercn added this to the Backlog milestone Nov 22, 2021
@ghost
Copy link

ghost commented Nov 22, 2021

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

@noseratio
Copy link
Author

noseratio commented Nov 22, 2021

A related comment by @SteveSandersonMS: #17099 (comment)

The future alternative solution
Longer term, we want to add another option to event handlers so you can tell the framework you want it to treat it as a two-way binding even though you're not using @​bind. In other words, to tell the framework you want it to enforce consistency between the .NET side and the DOM even when that means discarding the user's edits.

Also related: #17281

@MackinnonBuck
Copy link
Member

Closing this out because we now have @bind:get and @bind:set, which enable similar functionality.

@MackinnonBuck MackinnonBuck closed this as not planned Won't fix, can't repro, duplicate, stale Dec 5, 2023
@ghost ghost locked as resolved and limited conversation to collaborators Feb 7, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-blazor Includes: Blazor, Razor Components feature-rendering Features dealing with how blazor renders components
Projects
None yet
Development

No branches or pull requests

5 participants