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

Help with data persistance please.

I have an app that the user will input text in the settings portion and the data is sent to the device via the companion. the resulting string would be like the example below.

{"data":{"key":"userName","newValue":"{\"name\":\"Joe User\"}"}}

 

I need to have these settings stay with the device when the phone is not around. I attempting to write these settings to a file that the app can then access for the data but I am having issues constructing what needs to happen.

I have been up and down the FS API and File System Guides trying different things and combed through the community forums with no luck.

 

Can someone give a better explaination on how to do this?

 

 

Best Answer
21 REPLIES 21

See if this helps.

Peter McLennan
Gondwana Software
Best Answer
0 Votes

This gave a better insight but did not give me the answer I was looking for. It is possible my way of going about this is incorrect, so let me try to explain a bit more.

 

In my Settings/index.js I have 4 textInputs all identical to below.

 <TextInput
          label="Label 1:"
          placeholder="Label 1"
          settingsKey="label1"
          />

 <TextInput
          label="Label 2:"
          placeholder="Label 2"
          settingsKey="label2"
          />

 <TextInput
          label="Label 3:"
          placeholder="Label 3"
          settingsKey="label3"
          />

 <TextInput
          label="Label 4:"
          placeholder="Label 4"
          settingsKey="label4"
          />

 

Then in my resources/index gui I have a <text> placement for each.

   <text id="label_1" x="30" y="100"
        font-family="System-Bold" fill="black"
        font-size="30"
        text-length= "50"
        text-anchor="start">-</text>

   <text id="label_2" x="30" y="130"
        font-family="System-Bold" fill="black"
        font-size="30"
        text-length= "50"
        text-anchor="start">-</text>

   <text id="label_3" x="30" y="160"
        font-family="System-Bold" fill="black"
        font-size="30"
        text-length= "50"
        text-anchor="start">-</text>

   <text id="label_4" x="30" y="165"
        font-family="System-Bold" fill="black"
        font-size="30"
        text-length= "50"
        text-anchor="start">-</text>

 

In my companion/index.js I am using the standard messaging onchange events to move the data from settings to the app.

// Fires when a  user changes settings
settingsStorage.onchange = evt => {
  let data = {
    key: evt.key,
    newValue: evt.newValue
  };
  sendVal(data);
 
};

//Fires when the Message Socket Opens
// Restore any previously saved settings and send to the device
function restoreSettings() {
  for (let index = 0; index < settingsStorage.length; index++) {
    let key = settingsStorage.key(index);
    if (key) {
      let data = {
        key: key,
        newValue: settingsStorage.getItem(key)
      };
      sendVal(data);
    }}}

 

Then finally in my app/index.js file I am recieving the data sent from settings and making it display on the gui.

messaging.peerSocket.onmessage = evt => {

if (evt.data.key === "label1" && evt.data.newValue) {

let label1 = JSON.parse(evt.data.newValue).name;
    var label_1 = document.getElementById("label_1");
    label_1.text = label1;

}

if (evt.data.key === "label2" && evt.data.newValue) {

let label2 = JSON.parse(evt.data.newValue).name;
    var label_2 = document.getElementById("label_2");
    label_2.text = label2;

}

if (evt.data.key === "label3" && evt.data.newValue) {

let label3 = JSON.parse(evt.data.newValue).name;
    var label_3 = document.getElementById("label_3");
    label_3.text = label3;

}

if (evt.data.key === "label4" && evt.data.newValue) {

let label4 = JSON.parse(evt.data.newValue).name;
    var label_4 = document.getElementById("label_4");
    label_4.text = label1;

}

};

 

This will send and display the data as long as the watch has connectivity to the phone. I will need to write the data that is transmitted to a file which is stored on the watch. At which point, I will change my code so that the gui pulls the text to be displayed from the file. In addition, I need to be able to write/rewrite the file on watch when new data is entered or changed by the settings.

 

Ideally, I would like to compile the data in a single json file.

I am using the fs.writeFileSync method, but cannot get all the data into one file. If I use a seperate file for each entry, I am unable to overwrite the file when data changes.

 

So my question is what is the best method to save the data locally on the watch as it is being passed from settings on the onChange event?

 

Best Answer
0 Votes

At the end of your onmessage in the device app method:

 

 

let json_data={ 
"label1" : label1,
"label2" : label2,
"label3" : label3,
"label4" : label4
}
fs.writeFileSync('mysettings.txt', json_data, 'cbor');

 That would persist your settings into a file.

 

What of course you need to do then read them in on application start before you open the messaging socket to the companion.

 

 

let json_object = fs.readFileSync("mysettings.txt", "cbor");
label1=json_object.label1;
label2=json_object.label2;
label3=json_object.label3;
label4=json_object.label4;

Hope the above helps 🙂

 

 

 

Best Answer
0 Votes

Thanks for your help Rob. This has ALMOST got me where I need to be.

I have added this to my onmessage portion:

  let json_data = {
  "label1" : label1,
  "label2" : label2,
  "label3" : label3,
  "label4" : label4
  }
  //Put this in to verify that the file was written
  fs.writeFileSync('mysettings.txt', json_data, 'cbor'); 
  let json_read = fs.readFileSync("mysettings.txt", "cbor");

  console.log(json_read);
  //

 

And added this before my socket onopen portion:

//Load data from files to app at startup
let json_object = fs.readFileSync("mysettings.txt", "cbor");

//Verify that the file is read

console.log(json_object);

//

label1=json_object.label1;
label2=json_object.label2;
label3=json_object.label3;
label4=json_object.label4;
// Verify the the file has been read and associated with labels
console.log(label1);
console.log(label2);
console.log(label3);
console.log(label4);
//

 

However I am getting an "Unhandled ReferenceError: label1 is not defined" starting on the label1=json_object.label1; line.

 

I verified that the console.log line before it is indeed returning  [object Object]. 

Best Answer
0 Votes

In addtion -  if I do the following instead:

//Load data from files to app at startup
let json_object = fs.readFileSync("mysettings.txt", "cbor");
let label1=json_object.label1;

let label2=json_object.label2;
let label3=json_object.label3;
let label4=json_object.label4;

 

And then:

//Associate the labels with the index.gui
var label_1 = document.getElementById("label_1");
label_1.text = label1;
var label_2 = document.getElementById("label_2");
label_2.text = label2;
var label_3 = document.getElementById("label_3");
label_3.text = label3;
var label_4 = document.getElementById("label_4");
label_4.text = label4;

 

I get the data to persist on the device, however only label2 shows correctly where the others show "undefined". I am assuming because label 2 is the last bit of information sent onmessage so that is all that is written in json_data.

Best Answer
0 Votes

Hi @jomis003

 

You will need to make reference to your svg object before you can set it. My bad for not explaining more clearly. Am at work at the moment - I will post up a little later.

Best Answer
0 Votes

Hi @jomis003

 

Sorry didn't fully have my head on when first posting up:

 

You need to write the file after all settings have been received, the best place will be in a document.onunload function. Am just home from work - if you require it, I can post some code up tomorrow.

Best Answer
0 Votes

Hi - @SunsetRunner

I will work on that to see what I can do. If its possible to post a sample, that would be great!

Thanks in advance for your help./

Best Answer
0 Votes

Hi @SunsetRunner

 

I will work on it to see what I can do. If you could post some sample code, that would be great!!

 

Thanks in advance.

Best Answer
0 Votes

@jomis003

 

import document from "document";
import * as messaging from "messaging";
import * as fs from "fs";
import { me } from "appbit";

let label1text=document.getElementById("label1");
let label2text=document.getElementById("label2");
let label3text=document.getElementById("label3");
let label4text=document.getElementById("label4");

try {
  let json_data  = fs.readFileSync("settings.txt", "cbor");
  label1text.text=json_data.label1;
  label2text.text=json_data.label2;
  label3text.text=json_data.label3;
  label4text.text=json_data.label4;
} catch(err) { 
  // file does not exist
} messaging.peerSocket.onmessage = evt => { if (evt.data.newValue) { let textField=document.getElementById(evt.data.key); textField.text=JSON.parse(evt.data.newValue).name; } };
me.onunload = () => { json_data.label1=label1text.text; json_data.label2=label2text.text; json_data.label3=label3text.text; json_data.label4=label4text.text; fs.writeFileSync('settings.txt', json_data, 'cbor'); }

Went for the me.onunload instead of document.onunload as document.onunload didn't appear to function.

 

Hope that helps ....

 

Best Answer

Hi @SunsetRunner

When trying to run this code I am getting "Cannot set property 'text' of null"  on the line below:

 

  if (evt.data.newValue) {
    let textField=document.getElementById(evt.data.key.newValue);
    textField.text=JSON.parse(evt.data.newValue).name;
  }
};

My thought is that we are not writing the (evt.data.newValue).name to the settings.txt file as the data is being recieved by the app. Would we not still need to write the file within onmessage:

  let json_data = {
    "label1"://data for label1,
    "label2"://data for label2,
    "label3"://data for label3,
    "label4"://data for label4
  }
  fs.writeFileSync('settings.txt', json_data, 'cbor');

 

If so, then wouldnt the data need to be identified and set  as it comes in?

  if (evt.data.key === "labe l" && evt.data.newValue) {
    let label1 = JSON.parse(evt.data.newValue).name;

    var label_1 = document.getElementById("label_1");
    label_1.text = label1;

 

Am I thinking of this the wrong way?

Best Answer
0 Votes

@jomis003

 

Doh!! 

 

Change the me.onunload to

 

me.onunload = () => {
  let json_data = {};
  let label1text=document.getElementById("label1");
  let label2text=document.getElementById("label2");
  let label3text=document.getElementById("label3");
  let label4text=document.getElementById("label4");
  json_data.label1=label1text.text;
  json_data.label2=label2text.text;
  json_data.label3=label3text.text;
  json_data.label4=label4text.text;
  fs.writeFileSync('settings.txt', json_data, 'cbor');
}

Been a long week this week .... apologies for messing you about. Was trying to save a few lines of code and didn't test afterwards.

 

The above code is tested and it does work.

Best Answer
0 Votes

@SunsetRunner

No worries! Believe me when I say I appreciate all the help!

I replaced the code and am still getting the same error in the onmessage section. It is almost as if the code is not the data or writing the settings.txt when the onmessage fires. I am going to post some screen shots. Would you be so kind to look them over and see if I am missing something simple?

 

app index.js

appIndex.PNGindexGui.PNGsettingsIndex.PNG

Best Answer
0 Votes

@jomis003

 

In your SVG your text fields are label_1, label_2, label_3, label_4

 

In index.js you have label1, label2, label3 and label4 in the onunload code. Change these to include the underscores and all should be good there.

 

Then in settings.jsx change settingsKey to match, I.e. label_3 instead of label3.

Best Answer
0 Votes

@SunsetRunner

Thanks for the extra set of eyes. I made those changes and was still getting the same "Cannot set property 'text' of null" error on that line. 

 

I found what I needed to do was to define both the key and the value of the data coming in. 

messaging.peerSocket.onmessage = evt => {
console.log(`App received: ${JSON.stringify(evt.data.key)}`);
if (evt.data.newValue) {
let textField=document.getElementById(evt.data.key);

let labelName = JSON.parse(evt.data.newValue).name;
textField.text = labelName;
}
};

 

This allowed the data to change when changed in the settings and persist on the watch. Thank you for all your help with that!

 

Now the unintended consequence is that if I clear the settings using props.settingsStorage.clear, it sends a null back to the app, but the json_data is not reset back to its default state. The mysetttings.txt info still persists afterwards. 

 

I am researching on how to set it back to the default state as when the app was installed.

Best Answer
0 Votes

Check to see if the data received is null (===null) then delete the file (un sync it) is the first thought.

Best Answer
0 Votes

That was my first thought. I put in  the check for null. It doesn't seem to help.

 

if (evt.data.newValue) {
let textField = document.getElementById(evt.data.key);
let labelName = JSON.parse(evt.data.newValue).name;
textField.text = labelName;
}
if (evt.data.key === null) {
fs.unlinkSync("settings.txt");
}
};

 

Best Answer
0 Votes

Isn't JSON.parse(evt.data.newValue).name

going to contain the null value?

 

On a second thought, would it not be better to set each field to a default value?

 

Something like this maybe?

 

if (evt.data.newValue) {
   let textField = document.getElementById(evt.data.key);
if (JSON.parse(evt.data.newValue).name === null) {
let labelName = "Blank";
} else {
let labelName = JSON.parse(evt.data.newValue).name;
}
textField.text = labelName;
}

 

 

Best Answer
0 Votes

I am going to cirlcle back on removing values for now. What I have works great until I introduce an element like an additive list. I am working on adapting the code, but think I need a little better understanding of it.  

//onmessage event

  if (evt.data.newValue) {
  let textField = document.getElementById(evt.data.key);
  let labelName = JSON.parse(evt.data.newValue).name;
  textField.text = labelName;

 

If I enter "first label" into the first textInput label1 essentially what this is doing(correct me if I am wrong) is making the keyname(label1) equal to the value that is inserted. ("first label")

So essentially

label1=first label

 

Now we write the data to the settings.txt file

me.onunload = () => {
  let json_data = {};
  let L1Text = document.getElementById("L1");
  json_data.L1 = L1Text.text;
  fs.writeFileSync('settings.txt', json_data, 'cbor');
}  

 

When the app starts, it then reads the data and associates it to the gui

let L1Text = document.getElementById("L1");
try {
  let json_data = fs.readFileSync("settings.txt", "cbor");
  L1Text.text = json_data.L1;
}

 

Question - When we set the value "first label", how does it get associated with L1 on the gui?

 

Best Answer
0 Votes