ElementReference FocusAsync API#23316
Conversation
|
This looks great, and it's awesome to see the E2E test in there as well! I'm guessing this is marked draft because you're going on to do the "omit JSRuntime arg" bit, so I'll wait for updates :) |
pranavkm
left a comment
There was a problem hiding this comment.
This is really good! Just a few more things to address and we can get this in.
There was a problem hiding this comment.
Overall looks great!
I think we can tweak it a bit. I don't love the part where the IServiceProvider is spilled across the application and it feels that we are missing an abstraction.
I would consider creating an ElementReferenceFactory with an implementation on M.A.C.Web that plugs in the JS runtime. The JsonConverter and the Renderer only receive a ElementReferenceFactory and the ElementReference only holds on to whatever it needs on a given platform.
We would do something like
Renderer.ElementFactory.CreateWithUniqueId()and the remote RemoteJSRuntime would simply instantiate its own ElementReferenceFactory passing itself in the constructor.
That's a bit awkward because Additionally, although for high-level features it's generally fine to push code through factories and more abstractions, the perf costs are prohibitive for code in the deep guts of rendering. There are very legit cases for building many thousands of I also don't really have any particular objection to referencing the |
It's already holding on to the IServiceProvider, so I don't see the difference here. I'm saying, initialize it with the JSRuntime only and through a Factory instead of giving it the IServiceProvider. I think having the IServiceProvider there encourages customers to do We designed element references to be an opaque abstraction, and we should keep treating them like that. For that reason I would have the factory live on M.A.C.Web, make it responsible for populating the state, and using an internal type that only M.A.C.Web can understand (like an internal class WebElementState) that contains the JSRuntime. That way, the ElementReference is still opaque and we are still able to implement focus without any details leaking out.
I don't think what I'm proposing would have a negative impact on perf, it would be the opposite if anything. The factory is accessed from the renderer or is part of the converter and gives clear and scoped functionality. Then on the ElementReference we just have state as an internal property (object) that is populated with the IJSRuntime. The helpers then just do a In conclusion:
|
|
Thanks @javiercn. Having a factory with a default that just news up the a) It would be convenient if there was a default factory that constructed the type without state. interface IElementReferenceFactory
{
ElementReference Create();
}
ElementReference
{
public ElementReference(string id);
public ElementReference(string id, object? state);
}
Renderer.ElementReferenceFactory { get; } = ServiceProvider.GetService<ElementReferenceFactory> ?? DefaultElementReferenceFactory.Instance;
var newElementReference = Renderer.ElementReferenceFactory.Create();It might also be useful to also add an extension to public static IJSRuntime GetJSRuntime(this ElementReference reference)
{
return reference.State as IJSRuntime ?? throw "This hasn't been correctly configured.";
} |
|
@pranavkm Let discuss all this at the sync later today! Obviously with @MackinnonBuck too. |
|
Thank you for submitting this for API review. This will be reviewed by @dotnet/aspnet-api-review at the next meeting of the ASP.NET Core API Review group. Please ensure you take a look at the API review process documentation and ensure that:
|
pranavkm
left a comment
There was a problem hiding this comment.
I'll bring this up during API review on Monday and address any feedback separately. Let's get this in to avoid further merge conflicts
Summary of the changes:
FocusAsync()extension method toElementReferencethat focuses the element associated with the reference.FocusAsync()works properly.IJSRuntimeargument fromFocusAsync()Addresses #22892