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

Check/ clear all checkboxes and memory

ANSWERED

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"}`)
  };
});

 

Best Answer
0 Votes
1 BEST ANSWER

Accepted Solutions

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

 

View best answer in original post

Best Answer
14 REPLIES 14

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.

Best Answer

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. 

Best Answer
0 Votes

item0 is a document element and has to be accessed by its ID

document.getElementById('item0').value
 
BTW every character in javascript costs memory.
Reducing document.getElementById to a variable gets rids of a lot of unnecessary, redundant text and memory.
 
for example:

 

var gE=document.getElementById

if (gE('item0').value==1){
  //do stuff
}else{
  //do alternative stuff
}

 

 

Regards,

Reign

Best Answer

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!

Peter McLennan
Gondwana Software
Best Answer

@morningReign 

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. 🙂

Best Answer
0 Votes

@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.

 

ILuvChronoAnim.gifILuvChrono 

 

 

 

 

 

AstrolabeAnim.gifAstrolab

 

 

 

 

 

Regards,

Best Answer
0 Votes

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.

Best Answer
0 Votes

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.)

Peter McLennan
Gondwana Software
Best Answer
0 Votes

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?

Best Answer
0 Votes

@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.

Best Answer
0 Votes

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

 

Best Answer

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).

Best Answer
0 Votes

@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.

Best Answer
0 Votes

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

Best Answer
0 Votes