06-05-2020 22:11 - edited 06-05-2020 22:15
06-05-2020 22:11 - edited 06-05-2020 22:15
Hi,
If I want to use the Setting API to produce an ordered list of complex objects, say
{
firstName:string,
lastName:string
}
Since the AdditiveList is the only Setting UI that can be used to sort the order of a list of values, I think that's the only option I have. AdditiveList takes care of ordering values and deleting values, so far so good.
When it comes to adding a new value, it depends on an "addAction". The document mentioned, "addAction: a component that will be used to render the input style for this list. Should be a component that allows for input, such as Select or TextInput." However, I cannot find any component that allows input of a complex object - I don't want to give user a text input and ask them to input JSON 🙂
Then it looks like there's two possible solutions.
The first one, somehow make a component produce a complex object. Perhaps somehow allow a <Section> behave like an input to produce a complex object, while acceptable by <AdditiveList> as addAction? The problem is I cannot figure out how.
The second solution is what I'm working towards. The solution is not to use AdditiveList to add new object, only to sort the order and delete an object. Use other UI to allow user add a new complex object.
Then AdditiveList natively shows an "Add" button working with "addAction". I tried to make it disappear, not to mislead user. So far, I tried to give "addAction" a <Button>, a <Text>, and null. None of the usage is documented in API, so I'm taking some risk. The result is:
<Button> - does not show up
<Text> - displayed
null - runtime error
So my solution is, give the AdditiveList a Button or Text, anyway disable its add function, and add new object from elsewhere.
My question is: is there any better way to achieve this?
Thanks
Bing
Answered! Go to the Best Answer.
06-05-2020 23:24
06-05-2020 23:24
I forgot to show what the settings screen looks like when displaying the <select>:
06-05-2020 23:18
06-05-2020 23:18
I wonder if there might be another way to do this: React.
In this, I used a <select> to display a list. The list items can be added to, deleted or reordered. This was done by defining the <select> options with
options={slideSelectOptions}
slideSelectOptions is just a JS array. Whenever the array is manipulated in code, React takes care of redisplaying the <select>.
Obviously your .jsx has to provide an interface to allow users to indicate what they want done with the list, and those wishes are effected in JS by changing slideSelectOptions.
If you want a promo code for that app so you can see if the approach might work for you, let me know. But you can't have the source code!
06-05-2020 23:24
06-05-2020 23:24
I forgot to show what the settings screen looks like when displaying the <select>:
06-06-2020 09:08
06-06-2020 09:08
Hello Bing,
I haven't needed to sort in JSX, but I there are some more complex things you can do with the HTML generation, so you should be able to add sorting fairly easily to whatever control you want to use.
If you are using the basic structure of a Fitbit JSX file, it should look something like:
function mySettings(props) {
const { settings } = props;
return (
<Page>
<Section title={<Text bold align="center">My Title</Text>}>
<!-- rest of page here -->
</Page>)
}
You can nest useful functions within the mySettings function like
function mySettings(props) {
const { settings } = props;
function tgl(na){
var test = ["basket","triangle","apple"]
console.log(test.sort())
return <Toggle
settingsKey={`${na}`}
/>
}
return (
<Page>
<Section title={<Text>Test Section</Text>} >
{tgl("shSteps")}
</Section>
</Page>)
}
As shown, the array sort function will work here.
Regards,
06-08-2020 05:32 - edited 06-08-2020 05:52
06-08-2020 05:32 - edited 06-08-2020 05:52
Hi Peter,
Thanks for the tip mate!
<Select> would display the list, and the list can be manipulated. However it still needs other UI to allow user add the item, and re-ordering the item, cause <Select> itself does not do this.
I guess my best shot is still <AdditiveList>. At least it allows delete and re-ordering out of box.
Nevertheless, thanks anyway!
Bing
06-08-2020 05:39
06-08-2020 05:39
Hi morningReign,
Thanks for your reply. Sorry I didn't express myself clear enough. What I want is to allow user manage the order of the array of the complex objects, much like AdditiveList allow user to manage an array of simple texts, or manage an array of complex objects from selections.
My problem however is to allow user add a complex object with text input (like 'firstName' & 'lastName'), and able to reorder the objects. The fitbit API document only gave examples of handling simple text, or handling complex objects - but the complex objects can only be selected from a list of existing objects.
What I want to achieve is to allow user click "add" and input firstName and lastName, also allow user to re-order the list, and delete any of the input.
Anyway, thanks for the reply!
Best regards
Bing
06-08-2020 13:41
06-08-2020 13:41
The app I offered you maintains a list of items, each of which comprises about nine fields (including an image). The settings UI allows those complex items to be created, edited, resequenced and deleted.
You're right that ability to do those things required explicit coding in the companion and settings, because no out-of-the-box settings element can do it all. Half of the trick is trusting React to update the UI when the underlying source data (eg, array on which a <select> is based) changed. The other half is dynamic Settings code that appears and disappears depending on what the user wants to do. morningReign provided an example of this.
06-08-2020 13:48
06-08-2020 13:48
06-08-2020 16:52
06-08-2020 16:52
Hi Peter,
Woo that's a very complex setting, inspired me to do something similar. Thanks!
How do you get an image in Setting API? Nowhere in the documentation has any mention of allowing user uploading something or selecing an image. I have found out from other posts in this forum that fitbit has some undocumented features, such as a <Webconfig> tag, that some developers rely upon. How do I find those features? Where, if possible, can I find some documents about them?
Thanks again!
Bing
06-08-2020 17:14
06-08-2020 17:14
I didn't use any undocumented features. I used the <ImagePicker> to let the user select an image for the current slide ( = object = item). That component automatically puts the image into settings as a Base64-encoded string. You can read that string and setItem() it to an item-specific key in settings. That way, you can have multiple images in your settings, accessible via item number or whatever key you want.
Redisplaying the image later, including within a <TextImageRow>, involves reading the image strings back out of settingsStorage and associating them with the relevant settings components.
React takes care of updating settings components when the underlying data source (settingsStorage) changes.
06-08-2020 17:52 - edited 06-09-2020 05:22
06-08-2020 17:52 - edited 06-09-2020 05:22
Thanks for the reply. I realised <ImagePicker> is indeed in the Setting API document. It's just not listed in the guides document (https://dev.fitbit.com/build/guides/settings/) so that's why I missed it. Thanks for the tips again!
07-01-2020 03:45
07-01-2020 03:45
So, finally I got it. I worked out an example handling adding/removing/updating/reordering an array of "Person" objects, with two "pages", a list page and an add/update page.
Here's the code in typescript (in index.tsx)
interface Person {
name:string,
address?:string,
uuid:string
}
function uuidv4():string {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
function settingsComponent(props: Parameters<Parameters<typeof registerSettingsPage>[0]>[0]) {
const persons: Person[] = props.settings.persons?JSON.parse(props.settings.persons):[]
console.log("Rendering, "+JSON.stringify(props.settings))
if (props.settings.addPage === 'true')
return (
<Page>
<Section title={props.settings.curItem === undefined?"Add a Person":"Update Person"}>
<TextInput label="Name" settingsKey="newPersonName"
></TextInput>
<TextInput label="Address" settingsKey="newPersonAddress"
></TextInput>
{props.settings.curItem === undefined?
([<Button
label="Add"
onClick={()=>{
persons.push({
name: JSON.parse(props.settings.newPersonName).name as string,
address: JSON.parse(props.settings.newPersonAddress).name as string,
uuid: uuidv4()
})
props.settingsStorage.setItem('persons', JSON.stringify(persons))
props.settingsStorage.setItem('addPage', "false")
}}/>,
<Button
label="Cancel"
onClick={()=>{
props.settingsStorage.setItem('addPage', "false")
}}/>
])
:
([
<Button
label="Update"
onClick={()=>{
const original:Person = persons.find((p)=>p.uuid===props.settings.curItem);
if (original) {
original.name = JSON.parse(props.settings.newPersonName).name as string
original.address = JSON.parse(props.settings.newPersonAddress).name as string
}
props.settingsStorage.setItem('persons', JSON.stringify(persons))
props.settingsStorage.setItem('addPage', "false")
}}/>,
<Button
label="Cancel"
onClick={()=>{
props.settingsStorage.setItem('addPage', "false")
}}/>
])
}
</Section>
</Page>
)
else
return (
<Page>
<AdditiveList
title="Person"
description="Description of additive list"
key="w"
addAction={
<Button label="Add Person" onClick={()=>{
props.settingsStorage.setItem("addPage","true")
props.settingsStorage.removeItem("curItem")
props.settingsStorage.removeItem('newPersonName')
props.settingsStorage.removeItem('newPersonAddress')
}}/>
}
settingsKey="persons"
renderItem={
({name, address, uuid})=>
<Button label={name+","+address}
onClick={()=>{
props.settingsStorage.setItem('addPage', "true")
props.settingsStorage.setItem('curItem', uuid)
props.settingsStorage.setItem('newPersonName', JSON.stringify({name:name}))
props.settingsStorage.setItem('newPersonAddress', JSON.stringify({name:address}))
}}
/>
}
/>
</Page>
)
}
registerSettingsPage(settingsComponent);
07-01-2020 05:37
08-16-2021 06:18
08-16-2021 06:18
Hi. I was wondering what to do if this error happens?
uncaught-syntaxerror-unexpected-token-u-json
08-16-2021 13:37
08-16-2021 13:37
I think that can happen when trying to use JSON.stringify() on an undefined object.