Works PICK_ITEM by reference or by value?

Hi,

my assumption so far with AppGyver was: If I assign an item from a “collection of records” data variable to a “single record” data variable (e.g. with PICK_ITEM), the item values are copied.
From what I experienced it looks like it is only referenced, so if I change values in the “single record” data variable, the values in the record in the list are also changed.
Do you have some documentation on this behavior and is there a way to force a copy?

Thanks and best,
Jo

Hi there!

Can you post some screenshots of the logic in question and tell me a bit more about the exact usecase?

Hey,
during “Page focused” event, I use “set data variable” for setting a single record data variable (StudentFinancialCur) using the following formula:
PICK_ITEM(SORT_BY_KEY(data.StudentFinancialList,“recordScope”,“desc”), 0)

In my view, I bind the properties of StudentFinancialCur to input fields.
In addition, there is a possibility to switch StudentFinancialCur to the data of another list item with “set data variable” using the formula:
FIND_BY_KEY(data.StudentFinancialList, “recordScope”, current.recordScope)

Now, my impression is that the set data variable is not copying the data but rather just putting a reference to the list item into single record data variable. (but I would like to copy so that the data is only transferred to the list with an explicit “save” by the user)

Does this help?
Thanks,
Jo

Hi

I still want to check one thing to understand your issue. Are you setting a value for a “single record” data variable or “new record” data variable? Being that “single record” by default fetches a single record from the data resource I’m not sure why you would be setting it with ‘set data variable’? :slight_smile:

Hi,

no, I use a New Record variable where I put in the relevant item from the list via FIND_BY_KEY.

Best,
Jo

I am seeing the same issue. When I “Set a Page Variable” or “Set a Data variable” from an existing data variable it appears to be by reference not a copy.

In my first attempt, I created a data variable from a data resource as a “New Record” and removed the default data flow logic. All I wanted was a quick way to get a copy of the data resource schema (that is why I removed the default data logic).

The reason I wanted a duplicate data variable from a data resource schema is that I wanted to Copy the data from the “live” data resource variable to the duplicated (no data flow logic) so that when I have a screen that displays the data resource info and want to Edit that data, I can copy the current data to the copy such that when a user changes the data on the edit screen and then decides to Cancel the edits before saving them I can simply Copy the original data back into the data variable that has the live connection.

I created a screen that has a Toast component that shows (onComponentChange) the “copied” data as I changed the live data on the Edit screen. As I changed the live data the copied data was changed as well.

All this to say…it appears to be “by reference” not copied :frowning:

It would be great to understand if setting a data object to another data object always does “by reference” or if there is a way to request that it be a “copy”

I hope this helps describe the similar circumstances that I have seen (per what the OP is seeing)

Based on some additional testing, it looks like anytime you Set a Variable (data or page) at an Object level it does it by reference?

Instead of an individual properties level (using Object with Properties) copy item by item in an object which does a copy of each property so that a change to the originating object (and its properties) doesn’t change the object variable you copied data to.

@Steve_Stava
Hi thanks for the breakdown. I did some quick testing on my end and wasn’t able to observe quite what you’re describing. However this is also bit more unusual usecase for data variables which themselves have default logic etc. that complicates things somewhat.

If you’re okay with me taking a look at the app, could you provide the application id (https://platform.appgyver.com/builder/applications/1234567) and I could take a look at your example? :slight_smile:

Thanks for taking a look! I created a new test app, so feel free to do whatever you need to it: 152887

I have 2 sections in the test app.

The top section calls an API and fills in the dance name (just data I have to work with :slight_smile:) ). I have a copy button that copies (data object to data object) the API response data (name) to the Save data object (removed default logic). I have added a “Show DanceSave Name” button that shows the DanceSave.name value in a Toast component (this is relevant since the shown value is different than the value in the Toast after you change the name).

On the top section of the test app, you should see “Aurora” as the dance name. When you press the “Copy to Save Object” button you will see that same value show up in the “Name (Save)” component. That copy is in the DanceSave data object.

When you change the value in the “Name” field nothing changes in the “Name (Save)” field. But when you press the “Show DanceSave Name” button you will see the equivalent value shown in the “Name” field. This shows that the DanceSave object has the changed value but it doesn’t show in the input field.

Sorry for the long post…I will let you mess with it. Feel free to ask questions!

Thank you @Akseli_Virtanen and @Steve_Stava for following up on this. Just one additional comment from my side on why I dont see this as an unusual usecase:
Every time I want to allow the user to updates entries of a list with the possibility to discard or save changes made to a list item, I need a temporary list item object which initially gets the values from the list and is manipulated through bindings with the input fields. To build a “discard changes” function, I cannot just reference to the list item directly but need a copy which I can throw away for discard. The reason why I want to use a data variable here is:
There seems to be no way to create a page variable object based on a record structure. Building the variable manually is painful and error prone as I have many elements in the object and they may change.
If there are other ways to achieve this, please let me know!

1 Like

Even if data variables change their values locally, those won’t be saved to the backend before you use Update record Flow function.

This means if you want to discard the changes you can just A) Close the page user is working on B) Use Get record (collection) Flow function to get the saved data and allow user to start from scratch again

(I guess this isn’t optimal in some cases, but can be useful in others.)

Thanks Tomi, unfortunately my (Web)App requires a somewhat different layout, the list is on the left side and the selected entry is directly edited on the right side. So I guess I need to reload the data from the server for every discard or I get “JSON.parse(JSON.stringify(person));” working in a custom Javascript Flow function to do a deep copy manually.

In that case I’d probably create a backup copy of the record. You could e.g. put it into storage with Set item to storage (and use Get item from storage during Discard changes action), make a copy (of all data) to Client-side storage data resource or use another Data variable (or Page or App variable) to keep the data of the record under edit saved.

@Johannes @Steve_Stava

Thanks Steve for the excellent repro app, You are indeed both correct that the data variables in this scenario have quite sticky reference association. However I was able to come up with a relatively simple workaround by using this formula to set the ‘save’ variable (:

MERGE([ {}, data])

Hope this helps :slight_smile:

@Akseli_Virtanen and @Tomi_Laakso thanks alot!! Both solutions make lots of sense in different scenarios, this is really helpful.

2 Likes

Thanks for the MERGE approach! That is a great (and simple) approach to setting the whole object. I can see use for that in a few place :slight_smile:

1 Like