Dart JSON Encode/Decode causing error due to extra bracket - json

So I have a Flutter app which I'm trying to save some data locally as a JSON file. I'm doing this using dart:convert and jsonEncode and jsonDecode and a Dart Map, but for some reason when I save the Map to a file using file.writeAsString(jsonEncode(map)), it seems to be adding a phantom end bracket to the end like so (not consistently either it doesn't seem):
{
"posts_in_progress":
{
"https://dts.podtrac.com/redirect.mp3/chtbl.com/track/9EE2G/pdst.fm/e/rss.art19.com/episodes/67461d56-cdd8-4b03-a957-3edb110232d4.mp3":73035
}
}
}
This then causes an error when trying to read and decode this file with jsonDecode(file.readAsString()) because of the extra bracket.
What is causing this extra bracket? And how can I prevent this from happening or handle for the extra bracket when its there on the decoding side?
Edit:
LocalServices file which handles all the local data json storage. It doesn't seem to always happen and be easily reproducible, but it has happened multiple times (before I was just handling the local file saving and reading within other methods, but tried to create this local services class to help fix it, still haven't figured out what causes it tho).
import 'dart:convert';
import 'package:path_provider/path_provider.dart';
import 'dart:io';
class LocalService {
bool _isInitialized = false;
Map data;
String filepath;
String filename = 'local_data.json';
File file;
initialize() async {
filepath = await getApplicationDocumentsDirectory().then((directory) => directory.path);
file = await File('$filepath/$filename').exists() ? File('$filepath/$filename') : null;
if(file != null) {
print('Local Data File Exists, start decoding... \n${await file.readAsString()}');
data = jsonDecode(await file.readAsString());
print('Decoding complete!');
} else {
file = new File('$filepath/$filename');
data = new Map<String, dynamic>();
}
_isInitialized = true;
}
update() async {
if(!_isInitialized) {
await this.initialize();
}
try {
data = jsonDecode(await file.readAsString());
} catch (e) {
print('Error Updating file: $e');
}
}
Future<void> setData(String key, dynamic value) async {
if(!_isInitialized) {
await this.initialize();
}
try {
data[key] = value;
await file.writeAsString(jsonEncode(data));
await update();
} catch (e) {
print('Error writing update to file: $e\n$key/$value');
}
}
}

Related

Api call to json to interface to Mat-Tree

I'm running into issues with trying to convert a json response from an Api call into an interface that will be accepted by this buildFileTree. So the call is pulling from SQL, it is working in dapper, I also see the array of data in my webapp in my console. The issue is when I try to change the initialize() value for buildFileTree from my static json file 'SampleJson' (inside the project) to my new interface 'VehicleCatalogMod' the tree shows up with SampleJson but when I switch the data to VehicleCatalogMod, the tree collapses.
dataStoreNew: VehicleCatalogMod[] = [];
constructor(private _servicesService: ServicesService){
this._servicesService.GetVehicleCat()
.subscribe(data => {
this.dataStoreNew = [];
this.dataStoreNew = data;
console.log(data);
})
this.initialize();
}
initialize() {
this.treeData = SampleJson;
// Working as SampleJson this is where the problem happens
const data = this.buildFileTree(VehicleCatalogMod, 0);
console.log(data);
this.dataChange.next(data);
}
buildFileTree(obj: object, level: number): TodoItemNode[] {
return Object.keys(obj).reduce<TodoItemNode[]>((accumulator, key) => {
let value = obj[key];
const node = new TodoItemNode();
node.item = key;
if (value != null) {
if (typeof value === 'object') {
node.children = this.buildFileTree(value, level + 1);
} else {
node.item = value;
}
}
return accumulator.concat(node);
}, []);
}
GetVehicleCat(): Observable<any> {
console.log('Vehicle Catalog got called');
return this.http.get('https://api/right/here',
{ headers: this.options.headers });
}
I tried a multitude of different things to try & get this working. I'm pretty much stagnated. Same error occurs when I try this.dataStoreNew instead. No errors in console, it literally just collapses the tree into one non distinguishable line. Also when I used: const vcm = new VehicleCatalogMod(); it made the tree pop up with the different properties but not the API values.
I also attached an image of the HTML element that appears.
with VehicleCatalogMod
with SampleJson

How to make the function wait until response comes back

I am trying to add this response data to a zip object and later calling the createZip() method to download file as a zip file. Problem is my file getting downloaded first and the response is coming back. If I try to run the function again then right file is getting downloaded because in the previous API call I already got the response data.
Can anyone help me with this. I am new to angular and don't know how to use async/await properly.
zipFile = new JSZip();
exportIcsReportInJSONFormat() {
this.icsService.getICSReport()
.subscribe(response => {
console.log("JSONFile",response)
this.jsonFile = response;
this.zipFile.file("ics-report_.json", response, {binary:true});
});
To create zip file and download.
createZip() {
this.zipFile.generateAsync({type:"blob"})
.then(function(content) {
saveAs(content, "example.zip");
});
}
You can use the async/await pattern with Promises, something like this:
zipFile = new JSZip();
async mapZip() {
try {
var response = await this.exportIcsReportInJSONFormat();
console.log("JSONFile", response)
this.jsonFile = response;
this.zipFile.file("ics-report_.json", response, { binary: true });
var content = await this.zipFile.generateAsync({ type: "blob" });
saveAs(content, "example.zip");
}
catch {
...
}
}
exportIcsReportInJSONFormat() {
this.icsService.getICSReport().toPromise();
}

Minio return file ends in Converting circular structure to JSON error

I try to get a file from Minio and return it as a StreamableFile in NestJs.
Converting it in a StreamableFile throws a "Converting circular structure to JSON".
#Controller('cats')
export class MinioController {
#Get()
async uploadFile( ):Promise<StreamableFile> {
const minioClient = new Client({
endPoint: 'endpoint-url',
useSSL: true,
accessKey: 'accesskey',
secretKey: 'secretKey',
});
try {
const readerStream = await minioClient.getObject('bucket', 'test.pdf');
return new StreamableFile(readerStream);
} catch (e) {
return e.message;
// throw new Error(`Could not retrieve file from S3: ${e.message}`);
}
}
}

Best strategy for locally storing remote data in Flutter

I have a Flutter app that has to request a considerable volume of JSON data from the network. This data has to be converted into a Map.
The remote data changes like every week or so, so I am looking for a way to "cache" or permanently store it in order not to have to request it every time the user opens the app.
What would be the best way to achieve this?
If you want to do something quick, you can store that data in a file (source) using path_provider
Create a reference to the file location:
Future<File> get _localFile async {
final path = await getApplicationDocumentsDirectory();
return File('$path/counter.txt');
}
Write data:
Future<File> writeCounter(int counter) async {
final file = await _localFile;
return file.writeAsString('$counter');
}
Read data:
Future<int> readCounter() async {
try {
final file = await _localFile;
final contents = await file.readAsString();
return int.parse(contents);
} catch (e) {
return 0;
}
}
If you want to know all the options you have I suggest you read this: https://flutter.dev/docs/development/data-and-backend/state-mgmt/intro
You can use Hive lib to Save your data
import 'dart:io';
import 'package:hive/hive.dart';
part 'main.g.dart';
#HiveType(typeId: 1)
class Person {
Person({required this.name, required this.age, required this.friends});
#HiveField(0)
String name;
#HiveField(1)
int age;
#HiveField(2)
List<String> friends;
#override
String toString() {
return '$name: $age';
}
}
void main() async {
var path = Directory.current.path;
Hive
..init(path)
..registerAdapter(PersonAdapter());
var box = await Hive.openBox('testBox');
var person = Person(
name: 'Dave',
age: 22,
friends: ['Linda', 'Marc', 'Anne'],
);
await box.put('dave', person);
print(box.get('dave')); // Dave: 22
}

Where is the default save location Flutter

when I write this code:
onSubmit(){
if(csvname.isEmpty){
print('type name');
}else {
File csvFile = new File(csvname + ".csv");
print('yesssss');
}
}
Does it even create a csv file?
If yes where is it saved or how can I view it?
Full Code / pastebin
It is not saving it with the code you posted, see this doc. Here is an example on how to write to a local file:
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> get _localFile async {
final path = await _localPath; return File('$path/counter.txt');
}
Future<File> writeCounter(int counter) async {
final file = await _localFile; // Write the file return file.writeAsString('$counter');
}