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

Poor typing experience in Blazor Server app when manually binding to oninput event and using Azure SignalR Services #14242

Closed
danroth27 opened this issue Sep 23, 2019 · 6 comments
Labels
area-blazor Includes: Blazor, Razor Components question

Comments

@danroth27
Copy link
Member

danroth27 commented Sep 23, 2019

Repro steps:

  • Create a new Blazor Server app
  • Add the following code in index.razor:
@page "/"

<h1>Hello, world!</h1>

Welcome to your new app.

<input value="@message" @oninput="OnInput" />

<p>@message</p>

@code {
    string message;

    void OnInput(ChangeEventArgs e) {
        message = (string)e.Value;
    }
}
  • Run it and try mashing on the board when typing in the textbox. Works fine.

QyriWYUtKx

  • Publish to Azure App Service with the Azure SignalR Service
  • Browse to the published app and mash on the keyboard again. Poor typing experience.

hVsGL8FSxM

  • Publish to Azure App Service without the Azure SignalR Service, but with WebSockets enabled. Works fine.

ZLudipvtBQ

  • Switching the code to use @bind works around the issue.
@page "/"

<h1>Hello, world!</h1>

Welcome to your new app.

<input @bind="message" @bind:event="oninput" />

<p>@message</p>

@code {
    string message;

    void OnInput(ChangeEventArgs e) {
        message = (string)e.Value;
    }

}

ncW8ogiXKA

But in my case I need access to the oninput event callback to run additional logic.

@pranavkm pranavkm added the area-blazor Includes: Blazor, Razor Components label Sep 23, 2019
@javiercn
Copy link
Member

We can't bend the laws of physics. The issue here is the latency between the event arriving to the server and the data being applied on the client. Blazor server-side is not very well suited to use high frequency events, so the recommendation here is to debounce the event.

For example to trigger oninput on the client only after 100 milliseconds of the last event. I think that achieves what most people want. The event being fired without loosing focus from the control and without the jittering that you are observing.

I'm not sure what magic incantation we are using to fix it or "correct it" inside "bind".

@SteveSandersonMS Is my assesment correct? Do we have a sample for debouncing?

@SteveSandersonMS
Copy link
Member

Yes, @javiercn's assessment is correct. Dan implemented debouncing using a timer in his Weather app, and I also suggested there in a PR how it can be done with a CancellationTokenSource.

As for the issue posted here, this is a known limitation of reality and server-side Blazor that we've discussed and designed around in the past, e.g., #8204, #11438. The essence of the issue is a merge conflict: the server says the textbox is changing from A1 to A2, and the client says the current value is B. So who wins, A2 or B? Without more information, the best you can do is a "last write wins" strategy, which is what we do. This means we pick A2, since if we didn't, it would be impossible to write to the data from the server.

The reason that @bind can do better is that you're explicitly telling the framework about the two-way binding, so it can track internally how an incoming event matches up with some rendered output. It can then reason that, if the new rendered output is the same as what the client would already have in the DOM, then there's no reason to include this in the resulting diff, so we can prefer the client's value B. Whereas if the render output doesn't match, the server's value can overwrite the client's, so you can still mutate the data from the server.

As for improving this further, I've tried to think of ways we could extend the syntax for render output so you can manually associate it with a given incoming event. But I don't see any scenario for it outside two-way binding, and we already have a better syntax for that. Plus it's not an issue at all in client-side Blazor, so it's good to avoid having an entire syntax for things that only make sense in server-side Blazor.

But in my case I need access to the oninput event callback to run additional logic.

I think this is the real place where we can improve things. In your Weather app scenario, you do in fact have another option, which is to run logic inside a setter, as per my PR. However it would be better still if we didn't have the limitation of one-event-handler-per-event-type-per-element, and instead allowed you to combine @bind:event="onsomething" with @onsomething=....

@chrdlx
Copy link

chrdlx commented Sep 23, 2019

We can't bend the laws of physics.

@javiercn as @danroth27 pointed out, the issue doesn't happen if you don't use the Azure's SignalR service, With websockets only it works fine. So it's not related to a space/time fabric limitation =P

@SteveSandersonMS
Copy link
Member

That's not true I'm afraid. It happens regardless, as it's due to the latency, not due to the transport.

@danroth27
Copy link
Member Author

I think this is the real place where we can improve things. In your Weather app scenario, you do in fact have another option, which is to run logic inside a setter, as per my PR. However it would be better still if we didn't have the limitation of one-event-handler-per-event-type-per-element, and instead allowed you to combine @Bind:event="onsomething" with @onsomething=....

Yeah, I face palmed a bit when I saw your PR for not thinking of using the property setter solution, but it is a bit off the beaten track. Are we tracking the proposed improvement to allow multiple event handlers per event type somewhere else?

@SteveSandersonMS
Copy link
Member

Filed #14365

@ghost ghost locked as resolved and limited conversation to collaborators Dec 2, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-blazor Includes: Blazor, Razor Components question
Projects
None yet
Development

No branches or pull requests

6 participants