Cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Dynamically creating settings list from Json

ANSWERED

I am making a bunch of headway on my migraine app, but have run across a bit of a snag. 

 

I would ultimately like users to be able to log the initial migraine on the watch, and then edit it (add notes, update meds, etc) in the settings app.

 

I have figured out how to use all of the elements independently, record the headache, move tand sync the data,  launch a new page in settings etc. 

 

However, I am stuck at how to parse the Json in the settings app. Here is the general structure of the Json.

LekoFraggle_1-1627919279377.png

I have looked at this thread and see how to dynamically create a select object from Json.

I have also gone into the list docs for react, but many of the functions they use in the tutorial are unsupported. Can anyone direct me to any docs about how to get the Json data into a parse-able list that displays in the settings app?

 

I tried a for loop, but I keep getting the "Expected a function" error.

 

Any help would be appreciated.

Best Answer
0 Votes
1 BEST ANSWER

Accepted Solutions

As far as I know, you can only store strings. However, you can convert strings to JSON as long as they are formatted properly. And if you convert JSON object to strings, the formatting will be correct when you convert them back from storage.

 

Try the following:

 

 

 

// When writing to the settings storage (note i'm not sure the function you are using to write to the storage, so I'm making one up here. but toString() converts the json to a string

writeToStorage(myJsonObject.toString());

// When reading from storage, you should get a string i believe. Convert that to a JSON object

let myStorageStringConvertedToJson = JSON.parse(readFromStorage("WhateverKey"));

 

 

Thinking about it now, I would suggest you make sure your JSON object is formatted like the following:

 

let MyJSONArray = {
    "myJSONlist": 
    [
        {
          //obj1
        },
        {
           //obj2
        }

    ]
}

 

This will allow for converting the json array to a string much simpiler, since you can convert the entire thing at once rather than each individual object in the array

 

View best answer in original post

Best Answer
12 REPLIES 12

I don't know of any doc i can point you to off the top of my head, but a start (if you haven't done it yet) is to make sure you are formatting your JSON data correctly. Specifically, you need to make an array of JSON objects. For example:

let myJSONlist = [
    {
      "Migraine": 1,
      "Date": 1/20/2021,
      "Intensity": 7,
      "Meds": "zomig, Advil"
      //MORE FIELDS
    },
    {
      "Migraine": 2,
      "Date": 1/21/2021,
      "Intensity": 6,
      "Meds": "Advil"
      //MORE FIELDS
    }
];

Then, you can go through each element (JSON object) in this array like so:

myJSONlist.forEach((obj) =>{
  console.log("This is one object", obj);
});
Best Answer

Thank you. That was some of my confusion. I would do that, and that works outside of the page render (The react code), but inside the pager render react script, I get the following error.

 

S1382: Unexpected token. Did you mean `{'>'}` or `>`?
settings/index.jsx:100,41TS1005: '}' expected.
settings/index.jsx:101,1TS1381: Unexpected token. Did you mean `{'}'}` or `}`?
Error: Failed to compile /project/settings/index.jsx

Also, Mot of the react elements that people use are unsupported (ex. no  ```<li>```).

I have made some headway. I did have a problem with how I was forming the array as you suggested. I also found this tutorial which helped some. You can use their syntax in a ```<Text>``` object to create a react list. However, I still cannot figure out how to get each object. I will get it though. 

Best Answer
0 Votes

Alright, so here's a question then: Are you able to render anything on the page? even something simple (like a one line that you can show)?

Best Answer

Yes. Thank you. 

 

This code block shows a few examples I have been toying with. I am most interested in the button. 

 

 

 

 <TextImageRow
  label="Example"
  sublabel={migraineData.map((migraineData, index) => (
         <Text key={migraineData.Migraine}>{migraineData.Date}:{migraineData.Note}</Text>
      ))}/>
        
        <Button
  label={migraineData.map((migraineData, index) => (
         <Text key={migraineData.Migraine}>{migraineData.Date}:{migraineData.Note}</Text>
      ))}
  onClick={() => console.log("Clicked!")}
/>
        
        {migraineData.map((migraineData, index) => (
         <Text key={migraineData.Migraine}>{migraineData.Date}:{migraineData.Note}</Text>
      ))}

 

 

 

This produces the following...

LekoFraggle_0-1627949553362.png

 

Yet, I am not sure yet how to pull individual data out of *.map. 

Edit: In addition, it seems that typically, one would use Array.find, but that does not seem to be supported either.

Edit #2: The best option I am seeing for how to accomplish this by creating a button for each record. Then, the user can click it and get a new page with just the info for that record. However, to do that, I need to be able to access the individual record. Thank you again for your help.

Best Answer
0 Votes

Looking at the docs again (I love the Wc3 Docs), this is completely doable.

 

array.map(function(currentValue, index, arr), thisValue)

 

 

So it seems that...

  • index = the index of the individual item
  • arr = the object itself, and 
  • thisValue is the instance

 

{migraineData.map((migraineData, index) => (   
    <Button
        label={"Migraine Button " + index}
        onClick={() => console.log(index + " was clicked!")}
    />
    )
)}

 

Works as expected 🙂

 

Anyone trying this should also note from the docs that *.map() creates a new array. So, that impacts the editing process. However, *.pop() does seem to work, so that creates a path forward. Thank you again for your help.

Best Answer

Okay, so last night I had to go back to the drawing board.

While what I mention above works for Json arrays that stay in the settings app, I am unable to move anything other than a string from the settings/index.jsx to settings storage. Has anyone else had this problem, or know of a fix? Here is the error I get...

 

Uncaught AssertionError: Item value must be a string, current type of value is object

Oddly enough, I can put an array into settings storage from companion/index.js. I can also move an array of JSON objects, however, the objects get messed up so I cannot parse them once they are there. 

I am thinking of just moving the data as a string formatted JSON object and then reformatting it on both sides of the fence, but I was wondering if anyone had any other ideas. 

I am also wondering if this is a bug in the SDK v4.3, or if this is by design.

Regardless, I am learning a lot about programming with this project, so that is good 🙂

Best Answer

As far as I know, you can only store strings. However, you can convert strings to JSON as long as they are formatted properly. And if you convert JSON object to strings, the formatting will be correct when you convert them back from storage.

 

Try the following:

 

 

 

// When writing to the settings storage (note i'm not sure the function you are using to write to the storage, so I'm making one up here. but toString() converts the json to a string

writeToStorage(myJsonObject.toString());

// When reading from storage, you should get a string i believe. Convert that to a JSON object

let myStorageStringConvertedToJson = JSON.parse(readFromStorage("WhateverKey"));

 

 

Thinking about it now, I would suggest you make sure your JSON object is formatted like the following:

 

let MyJSONArray = {
    "myJSONlist": 
    [
        {
          //obj1
        },
        {
           //obj2
        }

    ]
}

 

This will allow for converting the json array to a string much simpiler, since you can convert the entire thing at once rather than each individual object in the array

 

Best Answer

Instead of .toString(), JSON.stringify() might be worth a try.

A variation (which I've used) is to store the array entries against separate settingsStorage keys; eg, myObjKey1, myObjKey2, myObjKey3, etc. Since the keys are just strings, you can fabricate these from the numeric array index easily enough. If your array has many entries, this could be more efficient because you don't have to get the whole array out of settingsStorage just to use one element.

Peter McLennan
Gondwana Software
Best Answer

Thank you. I think I am going to combine the strategies. They are helping.

I am having an issue with the data transfer. I am not sure how to create a valid buffer object to go from the companion to the app. 

Do either of you have any suggestions?

I can now successfully move data from the app to the companion, and from the companion to the setting app and vice/ versa. However, I cannot figure out how to send the JSON array to the device. I am assuming it is as a string, and I am assuming that I should use file transfer instead of messaging, but I am not certain. Thank you again for all of your help.

Best Answer

I wouldn't stringify the array for transfer from companion to app. That would just add length, and require the app to do more work to reconstruct it (and the device is relatively slow).

I'd convert it from settings string to array in companion, then use CBOR to transfer the array as binary data using "file transfer".

Peter McLennan
Gondwana Software
Best Answer

As to how to send objects to and from companion, you'll use the messaging api: https://dev.fitbit.com/build/reference/device-api/messaging/

Best Answer

Thank you for your help. @Gondwana thank you for your help as well. I did combine the two ideas and used JSON.Stringify(). It works perfectly. I am keeping the database in localstorage and only using setingsStorage as I need it. I wish I could choose two best answers 🙂

Best Answer