Reputation: 4966
I have 1 full page table component (custom, with column filters, sorting, dynamic loading, "infinite" scrolling and such), then a user clicks "edit" action on a row, it navigates to edit item page. Again, full page. It is a requirement it should visually be separate pages. 2 reasons: one big task a user does is searching, the bigger table, the more data - the better. The second task is updating some records. A single record is a very, very, VERY complex data set, it really needs as much screen space as possible.
The problem is when the user is done editing the record, the app navigates to previous page, but the table is reset, with default filtering, sorting and scrolling position.
Well, I can extract data from the table component and store it in a "pseudo-session" service data. The problem with that is I would have to add a lot of code to the table component - load / save state methods. Really lots of work (for each column filter element, then for column filter rows).
But there is a simpler way. Instead of using separate pages I could just fake it. Place both the table and row edit form on the same page, then just hide one part with JS / CSS. That should work, but IDK, it seems like an ugly hack to me. You render both parts, show one.
BTW, if you hide a component on server side in .razor
file and then show it again - it's reset. The constructor would be called, all parameters set to default, initial values.
Is there a way to hide a rendered fragment on server side and then show it without causing Blazor to reinitialize it?
Or a "back" function, that shows the last page in exactly the same state it was before navigation occurred?
UPDATE: I just tested the hiding option. Works as charm. Here's how:
<div style="@("display: " + (CurrentView == ViewOptions.List ? "block" : "none"))">
@* My list view here... *@
</div>
@if (CurrentView == ViewOptions.Edit) {
@* My edit entry view here... *@
}
Where ViewOptions
is just an enum
containing possible views. The CurrentView
is of type ViewOptions
. When CurrentView
is set to List
the first part is visible, the second part is not rendered at all. When it changes, the first part is hidden (but not destroyed), the second part is initialized and rendered. As my forms were already done as separate components, they take row identifier as parameter, and they trigger own event allowing to switch the CurrentView
back to list when the user is done with them. So we basically have 2 virtual pages on 1 page. A hacky solution but it works. And I've done that in 30 minutes instead of couple of hours I would spend to adding load / save features to my DataTable
component.
Still, maybe there is a better way? Or maybe it's optimal? Like... We have pages (unrelated directly with each others) and... SUBPAGES, like visually separate, but logically directly related to their parent pages.
That gives me an idea... What if I made a component called Subpage
? :) There is already a component called Page
in Blazor. So it would like complete the whole concept of pages and subpages. When the pages are not related directly - there's not much sense in navigating "back" to previous page. Or even maintaing the state of unrelated page. But the subpage is directly related. Its content depends on the parent page state. IDK, maybe it's too crazy to go that way ;)
Upvotes: 4
Views: 3171
Reputation: 5601
TL;DR: You are on the correct lower-effort path, I think.
The "correct" (or, rather, full, complete) way is to implement all the state storage (implement, expose, handle events, store that data somewhere like browser local storage or app state, etc.). As you found, toggling a component with a real if
resets it - that's where application state comes in - you keep the state in the events realted to changing it, then the next time a component initializes, it reads that state. But you have to implement it all on your own, and that's plenty of work.
So, there are two easier solutions:
as you found, hide the old content with CSS (if needed), and show the new content on the same page. If you show it in some sort of window/dialog, you may not have to hide the old content at all, though.
Or, use a component that someone wrote that already has those state capabilities built-in so you can just use them. Here's a commercial one I know of.
Upvotes: 2