ux icon indicating copy to clipboard operation
ux copied to clipboard

[LiveComponent] Design suggestion to keep the origin route

Open jcrombez opened this issue 1 year ago • 7 comments
trafficstars

This issue summarize a slack discussion

As already mentioned in a couple of issues usually about pagination using knp bundle, it's currently hard to create links using the same route as the origin context where a component is rendered.

A possible solution to that would be to add a trait, for example ComponentWithOriginRouteTrait like so :

trait ComponentWithRouteOriginTrait
{
    #[LiveProp]
    public ?string $routeName = null;
    #[LiveProp]
    public ?array $routeParams = [];
}

Then in a listener inject the values from the RequestStack at render time using PreCreateForRenderEvent.

As far as i understand the code, it's currently not possible to do that properly from "outside" (the app itself) for multiple reasons :

  1. PreCreateForRenderEvent only expose the component name, not its class so we can't check if the component has the trait.
  2. ComponentFactory who could give us the component class from its name isn't injectable.
  3. PreCreateForRenderEvent is expected to take care of the rendering by defining its own renderedString property, wich isn't ideal for this situation.

Of course given how common the issue is, i think it would be worth adding this to symfony/ux-live-component. If so, only [3] would still be annoying.

I also think it would be nice to let people do similar listeners so here is a few ideas to make it simpler :

  1. Either add the ComponentMetadata in the PreCreateForRenderEvent payload.
  2. Or simply make the ComponentFactory injectable.
  3. Give PreCreateForRenderEvent the ability to only change the component props before it's rendered, without the need to set renderedString.

jcrombez avatar Nov 28 '23 16:11 jcrombez

There is an ongoing-soon-to-be-merge PR about LiveComponent and url's that should, if I understand correctly, fullfill your need : https://github.com/symfony/ux/pull/1230

smnandre avatar Nov 28 '23 21:11 smnandre

There is an ongoing-soon-to-be-merge PR about LiveComponent and url's that should, if I understand correctly, fullfill your need : #1230

Maybe i don't understand the PR but it doesn't seems to give access to the origin route name and params, it adds the ability to bind url query parameters to LiveProps. Or did i miss something ?

jcrombez avatar Nov 28 '23 22:11 jcrombez

As already mentioned in a couple of issues usually about pagination using knp bundle, it's currently hard to create links using the same route as the origin context where a component is rendered.

It will help answering this problem, as the "page" is a URL query parameter

smnandre avatar Nov 28 '23 23:11 smnandre

If you want to have the route name, parameters, etc.. you can inject the RequestStack in your component as it is a service like any other.

smnandre avatar Nov 28 '23 23:11 smnandre

  • Either add the ComponentMetadata in the PreCreateForRenderEvent payload.

PreCreateForRenderEvent is an internal event used only to short-circuit the entire rendering process. It cannot expose the ComponentMetadata there because the metadata is loaded after this event is dispatched.

  • Or simply make the ComponentFactory injectable.

I believe today the idea is to keep it @internal, because this allows changes in the implementation that would be really difficult is it was public (BC breaks..)

  • Give PreCreateForRenderEvent the ability to only change the component props before it's rendered, without the need to set renderedString.

You can maybe take a look at the other events, i think PreRender may suit you.

smnandre avatar Nov 28 '23 23:11 smnandre

Thank you for this issue. There has not been a lot of activity here for a while. Has this been resolved?

carsonbot avatar May 29 '24 12:05 carsonbot

no

jcrombez avatar May 29 '24 12:05 jcrombez

Thank you for this issue. There has not been a lot of activity here for a while. Has this been resolved?

carsonbot avatar Nov 30 '24 12:11 carsonbot

Hi @jcrombez !

Some thought here:

First you need to get the information you want to store. You can

  • pass app.current_route and app.current_route_params to the component from your template
  • inject the Request Stack in your component constructor, ar any method : it is a service registered in the container (only this definition is "non-shared").
  • write things in some meta/data- attribute in the original HTML page, and fetch it from there via a stimulus controller, an event, etc etc

Then, storing the data in the state, via a non-writable LiveProp (as you show with your trait example) seems a good method. It will be then available as you like in the following / XHR re-renders.

You have here a legit need here.. but I don't think this would be that easy to generalise, as every app has its ows sets of rules and habits regarding routing, security, etc.

There is no special way/hidden magic we could use here, that you cannot implement yourself.

Again, it can be a good idea sometimes, but i don't think we want to promote this pattern too much, making the component dependant on external context, not just the props it exposes itself, and blurry.

I'm closing here because there has been no change in the past year. You can reopen one if you thing this is a mistake.

Have a nice day

smnandre avatar Nov 30 '24 15:11 smnandre