anmcgrath / BlazorDatasheet

Simple excel-like datasheet Blazor component
MIT License
131 stars 31 forks source link

Allow Focusing Datasheet Element #85

Open Zetal911 opened 1 week ago

Zetal911 commented 1 week ago

As seen on the demo page, when the user clicks a button outside of the datasheet, they are forced to click again onto the datasheet in order to resume typing. As default functionality this is fine, but it would be nice to expose a way to re-focus the datasheet so that the user can seamlessly resume typing after clicking an external button without needing to click back onto the datasheet where they were.

This is especially useful for button effects that change the users selection, so that they can then instantly start typing.

Fantastic component library by the way, it's incredibly flexible!

ADefWebserver commented 1 week ago

@Zetal911 - We can't know how the control will be consumed (for example what else is on the page). I don't think this is possible?

Zetal911 commented 1 week ago

AFAIK if the ElementReference for the Cells or Datasheet itself are exposed to the user, it's possible to call FocusAsync() on those elements in order to focus them. This would let me handle my own button events, perform whatever actions I want, and then set the focus back to the datasheet afterwards.

ADefWebserver commented 1 week ago

@Zetal911 -@ref="_datasheet" wont allow you to get the handler you need?

Zetal911 commented 1 week ago

@ADefWebserver The Datasheet class has ElementReferences inside of it that I can access using reflection, but I'd prefer to avoid using reflection if at all possible. The Datasheet itself can't be used for this directly, as far as I'm aware.

ADefWebserver commented 1 week ago

@Zetal911 - No need for reflection. This should work:

image

Zetal911 commented 1 week ago

@ADefWebserver Hi, I appreciate the help, but I don't see how that addresses the issue at hand. I'm not trying to set the focus to an arbitrary input field or other component that has an accessible ElementReference.

For clarity, when you do @ref="datasheet" on the component, it will give you a Datasheet object. The Datasheet class does not extend ElementReference, and it can't be used to call FocusAsync() or as a parameter to that Javascript function, since it is not a valid HTML element.

Hopefully this helps clear things up.

ADefWebserver commented 1 week ago

@anmcgrath - Perhaps exposing _innerSheet in https://github.com/anmcgrath/BlazorDatasheet/blob/main/src/BlazorDatasheet/Datasheet.razor will expose what is needed?

anmcgrath commented 1 week ago

Hi guys, at the moment the focus management is pretty rudimentary, there is a private variable in Datasheet.razor.cs: IsDataSheetActive. When this is false, key input doesn't trigger the editor to open which is what I think @Zetal911 wants to have more control over.

I can see that one method of giving more control would be to add a function to Datasheet.razor.cs such as SetDatasheetActive.

I don't know how well it would work triggering this on a button press for example, as the sheet itself listens to window events to set this flag but I'd be happy to give this a go.

Another issue with this is that if there is more than one datasheet on the page we would be relying on the user to manage which sheet is active. Not such a big problem I guess?

Zetal911 commented 1 week ago

@anmcgrath Hey! I just wanted to pop in to confirm that you are absolutely correct! My mistaken tunnel vision on HTML 'Focus' was a total red herring.

I just used reflection to set the IsDataSheetActive value to true after my button press, and it works completely as expected now which is fantastic.

For those curious, this was the line of I code I used. I'll keep this around for now, but I'll definitely keep an eye here to switch out of reflection as soon as I can!

typeof(Datasheet).GetProperty("IsDataSheetActive", BindingFlags.NonPublic | BindingFlags.Instance)!.SetValue(MyDataSheet, true);