UI for editing an array of strings (Form & ListView component?)

I'm trying to build an interface for editing a simple array of strings (no IDs/PKs).

Let's say the array of strings is provided in variable avar, e.g. avar.value = ["a","b","c"] and by "interface for editing" I mean ways to edit the strings, to change their order, and to add strings to the array or remove strings from it.

I'd assume that the new ListView component within a Form component is the recommended way to implement this. Each string would be mapped to an EditableText component sharing a container with some buttons for moving, adding, and deleting strings. Of course, the Submit button would have access to the resulting array of strings. Assigning a new value to avar and doing a form.reset() would start over again.

What would be the canonical way to set this up? (Is it even possible? E.g. what would be formDataKey of the EditableText components?)

There are several related posts in this forum but, honestly, it's all pretty confusing. State management under array mutations seems to be a mess.

my personal preference is to clone the original data set into a variable (like a local copy) and then point a listview at it - each component in the listview updates the local version of the data until the user is ready to hit save

quick example I just built to explain (doesn't include sorting but should give you the idea)


forum (2).json (17.0 KB)

Agree that there's probably a dozen ways to solve this and no "correct" one, I think that stems from it being a flexible platform that uses a lot of Javascript where this kind of open ended thinking is commonplace

4 Likes

Thanks for the super quick response! :slight_smile:

Do the following:

  • edit any of your strings
  • click the reset button (lower left)
  • notice that the reset does not actually reset anything (since it does not operate on textInput1.value but on its default value)

When I discovered this behavior during my experiments I thought that the form component must provide the required kind of reset functionality (or that there should be some kind of trick to set the ListView's primary key to something different than {{item}}). However, I couldn't find out how.

This approach by @ggallese only seems to apply for forms within a list view and only takes care of submitting/resetting row-wise.

The answer to this question by @bradlymathews does not apply since our case does not have row IDs.

This whole discussion including @seb's advice also does not apply or has the same problems with updating the edited text.

Anyway, the only workaround I could think of was to try to reset via "flushing" the ListView's data source, i.e. to first set it to the empty array [] and then to set it back to the desired field values. Unfortunately, this flushing didn't work within a single query but needed to be chained. At least, that's what I thought. When I tried to reproduce this with your setup it didn't work anymore. There's some weird caching(?) going on...

In the end, the only thing that resets the editable text is invoking its resetValue() method (see resetValue button in listview20230221.json). But that can only be done from within the scope of the ListView's item. :frowning:

It's surprising and frustrating to see so many topics on this issue and basically no response from Retool. We shouldn't have to come up with hacks to make a very simple design pattern work.

1 Like

@kschirrmacher, I think you're right. My original motivation to try/use Retool was that it would save me time, but, honestly, all in all I spent more than a day on this seemingly easy problem and I still don't have a clue what's the-Retool-way-of-solving-this might be.

4 Likes

It seems like they did something to change React's default behavior around re-rendering or updating the state that the children components use for their values to make the new List View much more efficient that just isn't quite working.

I wish they'd clue us into when or if it'll be fixed.

1 Like

My bad, sorry about that - this technique works ok in the "legacy list view", example attached, I'd forgotten that the new/performance listview is best suited for long read-only style lists and accessing child elements etc is a little problematic at best

Legacy version updates/change handlers seem to be wired differently.
I'll keep experimenting but I agree that this should be clearer and I worry that the "legacy" listview will one day vanish
forum (3).json (15.2 KB)

2 Likes

I've found this problem too. Managing state between the ListView's data source (an array variable in my case), the form's data, and the actual TextInput (which is repeated) is a nightmare.

However, I do want to note that we are making the assumption that this should be a common design pattern. There are a hundred other people in this forum demanding the same of their "common" design pattern. Retool can't do it all, but it's actually very good at doing a lot! So I've just revised how I solve my problem of a repeated, editable list.

The key things I wanted were:

  • new items could be added
  • existing items could be deleted
  • state was retained somewhere for saving later
  • Reordering was not required

2024-02-22_21-50-15 (1)

I can still get a list of values, which are editable. I can still add and remove from this list. And the variable remains up-to-date with my list values. Rather than adding and editing in the ListView itself, I use a modal to do the editing. I think it works quite well. I have attached the project, if that's helpful :smiling_face:

For the OP, perhaps the values in your list can just be Text/Markdown, and you can click them to open a modal and edit the value? Retool has reorderable lists too (amazing!), so those things combined might help get you to a workable solution! Good luck!

listview-modal-input.json (24.9 KB)

2 Likes

No worries @dcartlidge! I actually share your views on the "legacy list view" completely and thanks for your new json file. I think this might be the way I'll proceed for now. :slight_smile:

Thanks @hansontools!! Yes, I think you're right in that restricting the new ListView to read-only components makes sense and "outsourcing" editing to a modal certainly makes sense. I looked at your sample file (thanks a lot for that!) and you wrapped everthing in a Form without using any of its features. How would you use any form-specific functionality with the new ListView?

I wasn't using the form component for anything in particular, sorry. Just a repurposed app from something else.

I've broken these sorts of creates/updates into two parts, because I'll generally store these multiline data sets in a separate table to the bulk of the form.

So the form would save, using normal form-saving, and return an ID. Then I'll have an onSuccess handler query use that ID to save/update the multiline data in another table.

Quintessentially, I guess, it would be helpful if the Retool team could document that, currently, editable components cannot be reasonably used within ListViews -- not even within an outer Form component.

The currently available solutions are described above:

  • use the old legacy ListView or
  • use a read-only new ListView with a Modal for editing.

I believe this is being actively worked on :+1:

4 Likes

Hi there!

Thank you to @dcartlidge & @hansontools for sharing your ideas :pray:

We've been mainly suggesting sticking with the legacy list view for the time being if you need functionality beyond what @dcartlidge's first example provides

For some context on the launch, we launched the new list view before reaching feature parity with the legacy list view. We wanted to provide the option to benefit from the performance improvements as soon as possible, and we wanted to start getting user feedback as we're working on additional functionality.

As noted on this thread, the new list view still has a notable difference from the legacy one, in that it does't support indexing into child components to access their properties yet (see the scope warning on the launch announcement). This feature is being actively worked on and we are collecting feedback/ideas here. Since the new list view was completely redesigned to have better performance, indexing into child components will also need to be re-written and we want to be thoughtful about how we enable this feature. I'm not able to provide a specific eta for when it will ship, but I will post here if I get any updates internally.

We will not remove the legacy list view until we are confident that there is complete feature parity between the two, and therefore no reason to keep them both. Even when we deprecate a component (i.e. move it from the list of legacy components to the list of deprecated components), you can continue to use existing components in your apps. We only remove the option to create new deprecated components, and we usually maintain an option to still add new deprecated components behind feature flag - just in case!

4 Likes

Thanks for this update @Tess , very clear and good to know the legacy listview (which I use a lot) isn't going away yet

1 Like

Thanks @Tess! That's good to know and I'm actually very much in favor of Retool's publish-early approach here!

Can I just re-iterate that the problem discussed here and in other threads is not the lack of indexabilty of the new ListView, but the problems with editable sub-components. Just mentioning that in the docs would prevent false starts on the part of your users.

1 Like

Thanks for chiming in, @Tess.

As mentioned, this does seem like a distinct problem from the intended lack of indexing. Can you confirm that it’s intended or if this is a bug that can be corrected under the current scope of the component?

1 Like

Yes. I think it's possible retools agile approach is too aggressive. It wouldn't hurt to add in a little bit more common functionality before releasing a new feature. I find it disappointing to see that new feature sitting there but constantly knowing it won't do what I need and I have to use the old setup. I'm not sure who wouldn't be left feeling disappointed by the new feature actually, constantly being less than the old feature.

1 Like

Mostly, I just need to be able to reset child inputs to their default values. I make a lot of line item forms (purchase orders, invoices, sales orders) which make use of the list view for their entries. The issue I'm running into with the new list view is after I submit a "form" that has line items, I have no way to clear them, versus the legacy component which I can simply loop through all the children and set their values to whatever I need. The closest I can get is to force a reload of the entire app which sets all the relevant children back to their default, but that's hardly a useful solution.

If the goal of the new listview is primarily to improve performance, perhaps the happy medium is to expose event hooks that let the user define behavior, similar to how modules do it? I'm not sure what the overhead is for implementing something like that, but doing so would essentially push the onus to be performant back on us (the users). That way, the new listview would get the speed boost by default and for the main intended use cases, but we'd get the extensibility as well.

For me specifically though, simply a way to call listView.resetChildren() would be more than enough :slight_smile:

1 Like