Add the refresh_action
Add a new action, the RefreshAction, which, as the name suggests, provides a way to refresh the DataTable's content.
This is particularly useful when the data is updated from an external source, and the DataTable serves only as a display.
From my point of view, it's not exactly the same.
Firstly, it allows the DataTable to be reused in multiple contexts (potentially across several pages) without needing to know the URL to which it should be redirected. It simply redirects to the current URL, directly taking advantage of Turbo to update its content.
Secondly, redirecting to the page refreshes the entire page. Imagine a page containing four DataTables; all the data would have to be rebuilt again. Currently, given how Turbo works, that’s also the case (unless I’m mistaken). But we could change this behavior.
-> When refreshing a specific DataTable via a query parameter, we could indicate which DT should be refreshed.
-> In that case, within the handleRequest, if it isn’t the correct DT to refresh, don’t fetch the data—and therefore, avoid having to format it. Instead, return an “empty” DT. The complete page view would then contain the refreshed DT with its information and the three others empty. With Turbo refreshing only the frame corresponding to our refreshed DT, we would achieve the expected behavior.
-> Moreover, adding this option to refresh or not via handleRequest could also be used to make DataTables asynchronous. In other words, some tables containing large amounts of data (or simply taking a long time to load) might slow down the display of the entire page. We could add an option that initially doesn’t display any data in the DT, and then, once on the front end, refresh the frame and load ONLY that one DT.
I might be overthinking it, but I sincerely believe this would be an interesting feature to add to the bundle.
What do you think?
If the refresh action isn't merged, at least merge the data_table_name Twig extension function. If we want to return data table in a stream to replace current one, we need to do this currently, which is prone to break if this package changes the name in any way:
// prone to break on any name change
return new TurboStreamResponse()->replace("#kreyu_data_table_".$dataTableView->vars["name"], $renderedDataTable);
// this would be immune to that
return new TurboStreamResponse()->replace("#".$extension->getDataTableName($dataTableView), $renderedDataTable);
If the refresh action isn't merged, at least merge the
data_table_nameTwig extension function. If we want to return data table in a stream to replace current one, we need to do this currently, which is prone to break if this package changes the name in any way:
Data table name is not identifier of the turbo frame. It just so happens that name is a part of frame identifier in base theme. So, you would still have to do it like this:
return new TurboStreamResponse()->replace("#kreyu_data_table_".$extension->getDataTableName($dataTableView), $renderedDataTable);
I guess what you guys need is:
-
turbo_frame_idvariable in data table view, instead of relying on "kreyu_data_table_" prefix that can change in the future -
data_table_turbo_frame_idTwig function like @alexandre-castelain suggested, if you don't want to access the view vars directly
This could be expanded in the future allowing to define turbo frame identifier in data table options, or something like that, without breaking changes. Sure thing!
I'm up for data_table_name Twig function as well, but it needs to return name from the data table view.
@alexandre-castelain Thanks for the explanation, I think I understand it better now.
We can start by adding the data_table_turbo_frame_id Twig function, that will return the kreyu_data_table_{{ name }}, so we can expand it in the future without introducing breaking changes.
Secondly, redirecting to the page refreshes the entire page. Imagine a page containing four DataTables; all the data would have to be rebuilt again. Currently, given how Turbo works, that’s also the case (unless I’m mistaken). But we could change this behavior.
So, we want to be able to tell which data table to render as turbo stream in the controller, right? If we rely on some parameter in the request, it should be added to pagination controls, filtration form, URLs to sort, am I right? That's what I deduced based on your explanation in ActionRefreshUrlGenerator, but it shouldn't be available exclusively in refresh action.
I wonder if adding a live component that renders the data table wouldn't be good use case to render tables individually, instead of relying on turbo streams. Damn I'm soooo inexperienced with Turbo and live components it may be a total miss 😅
I think Turbo streams are the way to go. We have Form and Link actions which may go to any other part of our app, any endpoint. It's nicely decoupled and pluggable, and these endpoints may return the same data table with fresh data. Don't think that's possible with live components, because only they themselves are updated (as fsr as I understand them), unless we use some kind of event system or "action processors", that we could listen to and do something, which feels weird to me.
And no, Turbo won't refresh whole page, if you return response with only your table thats set to replace that one specific table.
And no, Turbo won't refresh whole page, if you return response with only your table thats set to replace that one specific table.
@FluffyDiscord if you define multiple data tables on one page, how do you know which data table to render via turbo stream? Do you rely on the turbo-frame header?
@Kreyu yes, I think so. It's what I understand looking at the turorial on SymfonyCast : https://symfonycasts.com/screencast/turbo/frames-find-frames#adding-the-turbo-frame-in-the-response
Reading through UX Turbo docs, this is my first thought on how would I handle this: https://gist.github.com/Kreyu/efa69130b531c07d41d2931f4f68bb30
This would mean no unnecessary queries in turbo streams, e.g. fetching products when interacting with categories.
Are we on the same page?
In the idea, yes, I think it's a good idea, but I would prefer to use the Trait (or another one) to simplify the work in the controller, like something like this : https://gist.github.com/alexandre-castelain/de62a66a455334152f2371fab562a9a6
We don't need to have multiple handleRequest depending if it's a Turbo call or not, in the handleRequest, we could use $request->headers->get('Turbo-Frame') to know if we need to fetch the data or not.
Created a discussion in #196 because most of that is out of scope of this pull request and it was easier to summarize a little bit 😄
Hi @Kreyu ! I changed the code :
- I added a configurable turbo frame identifier via option
- I removed the ActionRefreshUrlGenerator, as it was kind of useless.
- I added a default translation for the button Btw, if you don't want this feature, no problem, you can close this MR !
Closing in favor of #235 for turbo related improvements, keeping the refresh action outside of the bundle. Thanks for understanding 😄