06-10-2020 05:56 - edited 06-10-2020 06:11
06-10-2020 05:56 - edited 06-10-2020 06:11
Hello,
I have a few quick questions about checkboxes in a virtual list. Before I jump in, I am aware not everyone uses virtual lists to manage recycler activities, but it is the tutorial I have found, and though they require some odd workarounds, they do work well for me in general. I am open to other ideas of how to manage things.
I am working on a new app that uses an updatable list with checkboxes. Currently, I have it working using the tutorial found in the Guides.
I have everything working in general, but I am wondering if there is a way to have a check/uncheck all button, and where to find how to do that.
Also, I am wondering about how to save the checked state on the watch so that when someone checks the checkbox if the app times out (I would also be interested in the ability to control how long the app stays active), when the user opens it back up, the checked state persists.
Any documentation to help me understand how to solve these puzzles would be helpful. I looked at the file system API, and I think that would work, I just need to figure out how to get the state of the box so I can read then write it.
Thank you all again for all your help.
Edit: I think most of my questions can be answered by the following. I will not be able to work with it for a bit, but I will post when/if I figure it out.
import document from "document";
let tileList = document.getElementById("tile-list");
let tileItems = tileList.getElementsByClassName("tile-item");
let tileState = {}
tileItems.forEach((element, index) => {
tileState[index] = element.firstChild.value; // initial state
element.firstChild.onclick = (evt) => {
tileState[index] = !tileState[index];
console.log(`item ${index} :: ${tileState[index] ? "checked" : "unchecked"}`)
};
});
Answered! Go to the Best Answer.
06-13-2020 06:28
06-13-2020 06:28
Hello @LekoFraggle ,
Looking back at your original question:
element.firstChild.onclick = (evt) => {
tileState[index] = !tileState[index];
console.log(`item ${index} :: ${tileState[index] ? "checked" : "unchecked"}`)
};
You may want to try the more expanded function definition that delivers a 'this' variable referring to the calling element:
document.getElementById("testElem").onclick = function(evt) {
console.log(this.id)
};
// OR
function handleClick(evt) {
console.log(this.id)
};
document.getElementById("testElem").onclick = handleClick
This will give you access to both the ID of the element and the value thereof so that you may then store it in an object and ultimately a JSON or CBOR file.
The second version shown has each onclick event reference the same instance of the same function, while the first instantiates multiple copies.
Regards,
Reign
06-11-2020 10:25
06-11-2020 10:25
If you're wanting to persist values on the watch face, check out the file system (fs) API
I keep my persisted values in a JSON file that I check for and reload whenever the watchface restarts. I keep all persisted values in a single object that I write in a single operation.
06-12-2020 05:52 - edited 06-12-2020 14:12
06-12-2020 05:52 - edited 06-12-2020 14:12
Thank you, that helps. I was actually looking into it. My current issue is, I do not know how to read the item's state in order to put it into the json object.
My issue is that (once again), I am using a virtual tile list.
I can successfully find out if a tile was touched using this code.
import document from "document";
let VTList = document.getElementById("my-list");
let NUM_ELEMS = 100;
VTList.delegate = {
getTileInfo: function(index) {
return {
type: "my-pool",
value: "Menu item",
index: index
};
},
configureTile: function(tile, info) {
if (info.type == "my-pool") {
tile.getElementById("text").text = `${info.value} ${info.index}`;
let touch = tile.getElementById("touch-me");
touch.onclick = evt => {
console.log(`touched: ${info.index}`);
};
}
}
};
// VTList.length must be set AFTER VTList.delegate
VTList.length = NUM_ELEMS;
and can modify the SVG easily to add the checkboxes by adding the following to each element...
<use id="item0" href="#checkbox-tile" value="1">
<set href="header/text" attributeName="text-buffer"/>
</use>
Yet, if I try to implement the code in my post above for tracking the actual checkbox state...
(item0::value ="1" || item0::value ="0")
Either the code fails, or the state shows up as undefined.
Does anyone have any thoughts?
Thanks in advance.
06-12-2020 19:10
06-12-2020 19:10
item0 is a document element and has to be accessed by its ID
var gE=document.getElementById
if (gE('item0').value==1){
//do stuff
}else{
//do alternative stuff
}
Regards,
Reign
06-12-2020 19:21
06-12-2020 19:21
The fitbit build tools already contain minification, tokenisation and snapshot creation, so additional tactics in source code can actually require MORE memory. Test for best results!
06-12-2020 19:37
06-12-2020 19:37
I knew about item0, what I was struggling with is that I did not know how to access the .value. That is simple enough. Thanks. It is also neat to know about the simplification. I was wondering if I could gey away with that. I feel that with higher level languages it is easy to forget about memory implications of some choices.
@Gondwana that is good to know. And thanks to some other threads, I know how to check that. 🙂
06-12-2020 20:04 - edited 06-12-2020 20:33
06-12-2020 20:04 - edited 06-12-2020 20:33
@Gondwana wrote:The fitbit build tools already contain minification, tokenisation and snapshot creation, so additional tactics in source code can actually require MORE memory. Test for best results!
We've already had this conversation How-to-optimise-the-memory-usage
And you are right, ironically the easiest way to make your code larger, slower, and harder to read is in the attempt to 'optimize' it. Testing is in fact key:
import {memory} from "system"
var lm =(function(){
var mem = 0
var dlt
return(function(){
dlt = memory.js.used - mem
mem = memory.js.used
return("Mem:"+memory.js.used+"/"+memory.js.total+" Peak:"+memory.js.peak+" Pressure:"+memory.monitor.pressure+" Delta:"+dlt)})
})()
console.log(lm()) //RUN BASELINE TWICE
console.log(lm())
//PUT BASELINE CODE TO SIZE HERE
console.log(lm())
//PUT 'OPTIMIZED' TEST CODE TO SIZE HERE
console.log(lm())
But even making sense of the memory results can itself be counter intuitive due to javaScript's periodic, and somewhat unpredictable memory garbage collection.
Optimization techniques are probably beyond the scope for most of the questions asked here, and may even muddy the water, but for larger apps one definitely can use optimization to advantage.
Neither of the following apps will load without a more aggressive minification and some other optimization techniques.
Regards,
06-12-2020 20:28
06-12-2020 20:28
Hey Peter / @Gondwana ,
Since you are here and an MVP, do you happen to know if the review process is actually happening right now? I've had reviews in since the 23 of May and I know some have been waiting longer than that.
It would be somewhat understandable if Fitbit was on hiatus, with the current state of protest and/or unrest, but it would be nice to know the status and what to expect.
It would also be nice to know how the folks in the California offices are doing as we haven't heard from the more verbose like @JonFitbit or @LiamFitbit since before Memorial day.
06-12-2020 20:36
06-12-2020 20:36
The latest word on reviews is from JonFitbit: "We are working on it, things will start moving again very very soon." (Source: discord, 10:07pm.)
06-12-2020 21:09 - edited 06-12-2020 21:10
06-12-2020 21:09 - edited 06-12-2020 21:10
Thank you for that info. I have submitted my grade app, but it was just a few days ago, so with everything, I am not expecting much soon.
As for the initial question, I poked around a bit, and figured out another issue.
I am trying to merge two things in this guide.
The issue lies with that item0 (the element id).
So, the Virtual list reuses 10 svg elements and fills them with text.
I used the tutorial below the one I linked to to help me add the checkboxes.
However, when I load them, thought they work (I can check and uncheck them), when I try to access one by id, it still reuses the same 10.
If I try to access the state of checkbox in row 11, it fails.
To solve this, I can put the checkboxes in the reusable element in the beginning like so...
<svg>
<defs>
<symbol id="my-tile-item" href="#tile-list-item" focusable="false"
pointer-events="none" system-events="all" display="none">
<text id="text" />
<rect id="tile-divider-bottom" class="tile-divider-bottom" />
<use id="checkboxes" href="#checkbox-tile" value="0">
<set href="header/text" attributeName="text-buffer"/>
</use>
</symbol>
</defs>
Yet, when I do that, I think they all have the id of "checkboxes."
Does anyone know of a way to dynamically set the element id?
06-13-2020 06:13
06-13-2020 06:13
@Gondwana wrote:The latest word on reviews is from JonFitbit: "We are working on it, things will start moving again very very soon." (Source: discord, 10:07pm.)
Cool; that's very good to hear. Thanks for the info.
06-13-2020 06:28
06-13-2020 06:28
Hello @LekoFraggle ,
Looking back at your original question:
element.firstChild.onclick = (evt) => {
tileState[index] = !tileState[index];
console.log(`item ${index} :: ${tileState[index] ? "checked" : "unchecked"}`)
};
You may want to try the more expanded function definition that delivers a 'this' variable referring to the calling element:
document.getElementById("testElem").onclick = function(evt) {
console.log(this.id)
};
// OR
function handleClick(evt) {
console.log(this.id)
};
document.getElementById("testElem").onclick = handleClick
This will give you access to both the ID of the element and the value thereof so that you may then store it in an object and ultimately a JSON or CBOR file.
The second version shown has each onclick event reference the same instance of the same function, while the first instantiates multiple copies.
Regards,
Reign
06-13-2020 08:03
06-13-2020 08:03
Thank you. I will try this out and get back to you. This seems like it could work (I may need to use the first scenario you mentioned rather than the second so I could have access to which box was actually checked).
06-13-2020 08:56 - edited 06-13-2020 08:56
06-13-2020 08:56 - edited 06-13-2020 08:56
@LekoFraggle wrote:Thank you. I will try this out and get back to you. This seems like it could work (I may need to use the first scenario you mentioned rather than the second so I could have access to which box was actually checked).
The 'this' variable in javaScript always refers to the calling object, which in this case would be the calling checkbox. In fact, The 'short' function nomenclature also has a 'this', it just doesn't refer to the calling GUI element.
Note that local variables from outside an event handler are not accessible inside the event handler; they present as undefined.
06-13-2020 20:56
06-13-2020 20:56
Thank you. It is going to take some time to put the pieces together, but I think this is going to work. Each object is returning its state. I knew how "This" worked, but I did not know that it could be used on the individual elements in that manner