A way to tell if form fields in the app are dirty?

If a user is editing a record which is on a form one built, is there an easy way to tell if the data is dirty? When you make a table editable it is tracked there for you and it would be nice if it was also tracked on a form used for editing as well.

I can think of a few ways to track this myself of course, but we programmers are a bit lazy as you know.

1 Like

@bradlymathews what do you mean by “dirty?”

Dirty is a term used to flag if data or state has changed. Many frameworks that do form input/edit have a .dirty property you can check to see if you should bother saving changes or send an alert to the user to see if they want to save changes.

1 Like

@bradlymathews I think it depends on how you’re using your form - if it’s just a bunch of inputs, it’s not clear what the “existing” data is. You could use the “placeholder”
or “default value” settings in a text input or dropdown to reference a selected row in a table or something like that.

But if you just mean persisting state between sessions / sending a notification if a user is about to delete form work, that’s a bit more complex. I wonder if you could use something like utils.sendNotification

I have a working solution to share. Concat all of the original values of the fields into a variable. In my case the source is table.currentRow. Then do the same with the actual values in the form fields. Then in your Save button Disable When test just see if they are the same.

In my case I am using Temp State vars to hold the cached field states.

formDirtyCache1=
{{tblProducts.selectedRow.data.product_name +
tblProducts.selectedRow.data.town_id + 
tblProducts.selectedRow.data.price+
tblProducts.selectedRow.data.product_description+
moment(tblProducts.selectedRow.data.last_inventory_check).format('YYYY-MM-DD')}}

formDirtyCache2=
{{txtProductName.value +
selTown.value + 
txtPrice.value +
txtDescription.value +
moment(dtInventoryCheck.value).format('YYYY-MM-DD')}}  

Disable when on Button = 
{{formDirtyCache1.value == formDirtyCache2.value}}

If I need to use this in more than one place in the app, I could create another temp var keep it DRY:

formDirty = 
formDirtyCache1.value != formDirtyCache2.value}}

Notice how I need to do a little extra work on the dates because the table and the datetime picker return the date in different formats and I need to normalize these to get a proper comparison.

2 Likes

Here is the approach I took to solve this (a little time consuming):

  1. For each field in your form, add a ev1. ent handler using the on "Change" trigger that will compare value that is loaded when the form first opens and compare it against the new value (if any) AND set a temporary variable (I named mine: "IsDirty") which I can then
  2. Ex: {{( formQuery1.data.Title.toString() != Title.value ? 1 : 0 )}}
  3. This example I am using a form to edit existing values, hence the formQuery1 loads the data so fields are populated with the corresponding db values. The Title.value is the field in the form and if that changes I then set the temp variable "IsDirty" to either 1 or 0.
  4. I can reference that in over events / queries to reopen the modal if closed while it was still dirty.

What I did was hide the modal close button via css (ex: span.ant-modal-close-x { display: none;} ). Then I added my own button inside the modal to close it, but before using the modal1.close() method, I check the IsDirty temp variable and take action if needed.

This is really something that a "low code" tool should already natively have built in capabilities of handling. I hope the Retool team is paying close attention.

Thanks for this workaround, @Funkdaddy!

I'll move this thread over to feature requests :blush:

Here is a screenshot on what I did to help others :slight_smile:

For context: I have a modal open via "row click" event, which then displays a modal allowing me to edit existing record or add a new one (which I also control the form via temp state to determine if it's going to be an insert vs update query).

I hide the "X" close button on modals via CSS. Then notice I added the "Close" button in the modal's upper right corner. Now, when closing the modal I check the IsDirty temp var and dynamicaly display the additional WARNING modal (if temp var is not dirty then WARNING modal doesn't fire, I simply close the main edit modal).

Ex

if( IsDirty.value == '1'){
  modalWarn.open();
}else{
  modal1.close();
}

+1 on this feature

+1, for example react-hook-form makes this kind of thing very simple with ergonomics like isDirty as a property on fields.

1 Like

I did figure out an easier way to do this, but a native method is preferable.

2 Likes

+1