Manipulate data in nested Lists. Example Countries API

I really need help to how to manipulate data in nested lists/objects.
And example is the Countries API. Tutorials show how to list data, but we often want to change them.
So here is a list with country-name and their languages for each country.
I want to change them. Ex. with a button or a click on any name/language.
How to do this?

I can can change the country-name with
Button: SET_ITEM_AT(data.countries_list, 0, SET_KEY(item, “name”, “Norway”))
Click on name: SET_ITEM_AT(data.countries_list, repeatedInfo.current.index, SET_KEY(item, “name”, “Norway”))

But I just can’t figure out how to go one level down to languages and change one of them.
Any help? Is it even possible?

1 Like

Some hours later I have a solution on the other two challenges. Maybe this can help others. And maybe there is a better solution as the second one here looks a bit “ugly” (not “no-coding-looking”…).

The data looks like this
[
{
“name”: “Afghanistan”,
“languages”: [
{
“iso639_1”: “ps”,
“iso639_2”: “pus”,
“name”: “Pashto”,
“nativeName”: “پښتو”
},
{
“iso639_1”: “uz”,
“iso639_2”: “uzb”,
“name”: “Uzbek”,
“nativeName”: “Oʻzbek”
},
{
“iso639_1”: “tk”,
“iso639_2”: “tuk”,
“name”: “Turkmen”,
“nativeName”: “Türkmen”
}
],
},
{
“name”: “Åland Islands”,
“languages”: [
{

]

Tap Button to change Uzbeck under Afganistan to Norwegian:
MAP<countries>(data.countries_list, IF(index === 0, SET_KEY(countries, "languages", MAP<langs>(countries.languages, IF(index === 1,SET_KEY(langs, "name", "Norwegian"),langs) ) ), countries))

I’ll try to explain:
//run trough all countries. Also give each object the name countries
MAP<countries>(data.countries_list,
//if the index is 0, it is the first object Afganistan
IF(index === 0,
//we found our object, no we want to change it - we use the name we gave in first line
SET_KEY(countries,
//we want to change the values in languages
"languages",
//But languages is a list of objects, so we run through this and also give the name langs
MAP<langs>
//we go down one level in our first object
(countries.languages,
//we only want to change the second object in the languages-list, so check for index 1
IF(index === 1,
//we want to change this by setting the property name to correct value
SET_KEY(langs, "name", "Norwegian"),
//if we are not on index 1, we just return the current object with the given name langs
langs) ) ),
//this is the end of the first if that got the first country object. If not index 0, we just return the object
countries))

Tap on any languages and change it to Norwegian
MAP<countries>(data.countries_list, IF(index === INTEGER(SPLIT(outputs["Receive event"].componentInstanceId, ":")[3]), SET_KEY(countries, "languages", MAP<langs>(countries.languages, IF(index === repeatedInfo.current.index,SET_KEY(langs, "name", "Norwegian"),langs) ) ), countries))

This follows the same pattern as above, but we need to replace the index-values with the correct ones as we tap. When we tap a language we need to get the index of the current country-object. We do not get this info from the repeatedInfo. That only gives the index of the tapped language (repeatedInfo.current.index).

So after some trial and error I found what seems to be the id Appgyver gives to elements.
The outputs["Receive event"].componentInstanceId outputs something like this:

page.Page6:4c12ace8-aa29-4323-a11d-054575352226:f9e54151-4b99-4be4-b31d-9bf553476acf:0:f9e54151-4b99-4be4-b31d-9bf553476acf:1

You can split this with : using SPLIT() and you get a list
[
“page.Page6”,
“4c12ace8-aa29-4323-a11d-054575352226”,
“f9e54151-4b99-4be4-b31d-9bf553476acf”,
“0”,
“f9e54151-4b99-4be4-b31d-9bf553476acf”,
“1”
]
So this looks like starting with page and going down and at index 3 you get the index of the country (the parent index we are looking for. Here 0). And also at index 5 we get the languages index we tapped on, here 1.

So using this, get the index [3] and you have the Country-object index.
INTEGER(SPLIT(outputs["Receive event"].componentInstanceId, ":")[3])

I dont really like this. Hope someone know if this is correct or if there are any other better solution. There should be, as it is just so fundamental to work with nested lists/objects.

I would like to give another solution on changing one of the languages which I now think is more correct and “The Appgyver way”.

This solution can you also use on most of nested lists/object.

The problem is, when you click on one of the languages, you only get the current object in the list of languages. You don’t know which of the countries-object you are in. Or in a nested list you can say you get the child-object, but not the parent-object (or root) you are in.

So you need a connection from the child-object to the parent-object. From languages-object to country-object.

If you can edit the data-source/API you create the connection there or as in the countries example, you cant edit the source, so edit the data before you use it like this:

Go to Data and the Schema of country list. Add a property to languages. In this example countryname. In other lists you could call it parentID or something else.

Then go to Variables and select Data variables and in the Logic flow you add Set Datavariable


and set it to this formula:
MAP<countries>(data.countries_list, SET_KEY(countries, "languages", MAP<langs>(countries.languages, SET_KEY(langs, "countryname", countries.name))))

What we do here is to run trough all the countries-objects where we want to change the “languages” list
MAP<countries>(data.countries_list, SET_KEY(countries, "languages",
We then run trough all the languages-objects and set the property countryname to the country.name.
SET_KEY(langs, "countryname", countries.name)

Then we have a connection from languages to country-object. In other nested list you may use some kind of id if the parent-object has one. Here we assume the country-name is unique.

So when we now tap a language, we can MAP trough all countries and search for a country.name same as the current.countryname. When found, we run trough the languages and change the object with same index as current index. Same as above.
So it would look like this:

MAP<countries>(data.countries_list, IF(countries.name == current.countryname, SET_KEY(countries, "languages", MAP<langs>(countries.languages, IF(index == repeatedInfo.current.index, SET_KEY(langs, "name", "Norwegian") , langs))) , countries))

The important here is
IF(countries.name == current.countryname ...
Where we find the parent-object.

Hope this helps. It has helped me in understanding nesting og manipulate the data. In an other project I needed a checkbox to ingrediens in a list of categories. So used this technique to check/uncheck ingrediens.

If you have a third level you will need a same connection form level 3 to level 1 and level 2, from level 2 to level 1. Have not tried this yet. But deep nested lists seems complicated in Appgyver, so keep it simple. But 2 levels are very common.

Hi @ Alf_Georg_Ostebrot

I’ve a similar problem here. Can you please have a look?