Hi there,
I am trying the Storage Module and it seems not to work. The console logs that the file has been saved by showing the token - this event happens after the user inputs the new string and clicks a button. But when I try to read from the same file, the JSON parsed is NULL.
The idea : The user inputs a string or sentence which is saved as an object such as { id : ‘id’, data : ‘data’, time : ‘time’ }. When the data is fetched, I would like it to fetches all the saved strings as a JSON, such as { wholedata : [ { id : 'id', data : 'data', time : 'time' }, { id : 'id', data : 'data', time : 'time' } ]} so that I can loop through and update the observable that is also updating the UX.
Here is the JavaScript code:
// The constants
var Observable = require("FuseJS/Observable");
var Storage = require("FuseJS/Storage");
var SAVENAME = "nau.txt";
var r_date = new Date();
// Variables
var data = Observable();
var save_new = Observable("");
function getdata() {
// Get the data from the file
Storage.read(SAVENAME).then(
// First function if successful
function(content) {
var read_data = JSON.parse(content);
// Save the data in variable, if there is data
if( read_data.wholedata.length > 0 ) {
for( var i = 0; i < read_data.wholedata.length; ++i ) {
data.add( {
counter : read_data.wholedata[i].counter,
data : read_data.wholedata[i].data,
date : read_data.wholedata[i].date
});
}
}else {
console.log('No data to read ' + read_data.wholedata.length);
}
},
// Second function if not sucessful
function(error) {
console.log(error)
}
);
}
// Run getdata on initialize
getdata();
function savenew() {
// Get the value to store in the storage file
var counter_to_store = data.length + 1;
var data_to_store = save_new.value;
var date_to_store = r_date.toDateString() + " - " + r_date.getHours() + ":" + r_date.getMinutes() + ":" + r_date.getSeconds();
// Save data in variable
data.add({
counter : counter_to_store,
data : data_to_store,
date : date_to_store
});
// Save in file
var storeObject = { wholedata : data.value };
Storage.write(SAVENAME, JSON.stringify(storeObject)).then(
function(wasSuccess) {
if(wasSuccess) {
Storage.read(SAVENAME).then(
function(content) {
var storedToken = content;
console.log('token = ' + storedToken );
}
);
}
}
);
}
first of all, FileSystem is preferred over Storage. Aside from that, Storage totally works; it’s a problem with the logic in your code. In particular, this line isn’t how you should be treating an observable list:
var storeObject = { wholedata : data.value };
there, you’re essentially only ever reading the first item in the list, which I’m sure isn’t what you wanted.
Here’s a complete, minimal, fully working example of doing what you were after:
<App>
<JavaScript>
var Observable = require("FuseJS/Observable");
var FileSystem = require("FuseJS/FileSystem");
var path = FileSystem.dataDirectory + "/" + "mydata.json";
var data = Observable(); // data is going to be an observable list
var inputString = Observable(""); // inputString is just an observable string
function read() {
// check if file exists, and if not, create it with an empty array string representation
if (!FileSystem.existsSync(path)) writeStringToFile("[]");
// and then, read the file and update data observable with the array of items
FileSystem.readTextFromFile(path).then(function(str) {
var arr = JSON.parse(str);
console.log("read data, length: " + arr.length);
data.replaceAll(arr);
});
}
// save function creates a string representation of array
// that is taken from the data observable list
// and then calls the function that does the actual saving to file
function save() {
writeStringToFile(JSON.stringify(data.toArray()));
}
// since we're only storing string contents, let's have a function for that
function writeStringToFile(str) {
FileSystem.writeTextToFile(path, str).then(function() {
console.log("saved");
// we do not need to call read() again, because the data observable
// holds the latest data already anyway
}).catch(function(e) {
console.log("not saved: " + e);
});
}
// when user hits enter in UI, we add the item to the data observable
// then clear the text input value
// and save the now-modified list to file
function addItem() {
data.insertAt(0, inputString.value);
inputString.value = "";
save();
}
// just for testing, we also have a way to clear the saved data
// where "clearing" is writing an empty array string representation to the file
function clear() {
writeStringToFile("[]");
// we could just call data.clear() now, but since we're lazy
// and we know that read() will update the data observable,
// we can just call read() here
read();
}
// on app init, read the file
read();
module.exports = {
data: data,
addItem: addItem,
inputString: inputString,
clear: clear
};
</JavaScript>
<ClientPanel>
<Panel Height="56" Dock="Top" Color="#f81">
<TextInput Value="{inputString}" Height="56" TextColor="#fff" Margin="4">
<TextInputActionTriggered>
<Callback Handler="{addItem}" />
</TextInputActionTriggered>
</TextInput>
</Panel>
<Panel Height="56" Dock="Bottom" Color="#81f" Clicked="{clear}">
<Text Value="Clear saved" Color="#fff" Alignment="Center" />
</Panel>
<ScrollView>
<StackPanel Margin="4" ItemSpacing="2">
<Each Items="{data}">
<Panel Height="56">
<Text Value="{}" Color="#fff" Alignment="Center" />
<Rectangle Color="#18f" CornerRadius="2" />
</Panel>
</Each>
</StackPanel>
</ScrollView>
</ClientPanel>
</App>