0

In my Angular program, have a class called myObj and an array called myArrayObj, that contains many instances of myObj.

I am currently storing it into Blob and write into file, as shown below.

    const blob = new Blob([JSON.stringify([myArrayObj])], { type: 'application/json' });
    saveAs(blob, `${myFileName}.json`);

To retrieve content from file, I have another set of codes.

    const fileReader = new FileReader();
    fileReader.onload = (e) => {
       const content = e.target?.result;
       if (typeof content === 'string') {
          const myArrayObj = JSON.parse(content);
       }

My problem is that I want to save a single setting object (mySettingObject) into the file, before this array. How do I do that? How do I retrieve the setting object and array later?

4
  • could you try new Blob([JSON.stringify([mySettingObject, myArrayObj])], { type: 'application/json' }); Commented Nov 3, 2024 at 15:53
  • But how do you read the objects out? Commented Nov 3, 2024 at 23:05
  • sounds like XY problem. could you add more context, what is the goal, why are you storing it in a file, instead of sharing it via service etc. Commented Nov 4, 2024 at 7:56
  • I am just doing a simple POC so don't intend to complicate things too much by adding a login mechanism and service. The setting object will just be some preference setting, and is something good to have. Commented Nov 4, 2024 at 14:46

2 Answers 2

1

My problem is that I want to save a single setting object (mySettingObject) into the file, before this array.

You can't. At least, not directly.

Normally, JSON parsers only work on one root object. Therefore, you'd have to serialize an entire object that contains your array as well.

JSON.stringify({
  mySettingsObject,
  myArrayObject
});

In this case, there's a singular root object that you can reference properties on, which is perfectly fine.

An alternative... there is a variant of JSON that uses line delimiters called ND-JSON. This allows multiple root objects, but the usual use of it is for multiple objects of the same or similar type. While this isn't a requirement, I'd think your use case is inappropriate.

Sign up to request clarification or add additional context in comments.

Comments

1

We can create a complex object, with two properties settings (which holds mySettingObject) and array, then we perform the download.

downloadFile() {
  const mySettingObject = {
    qwerty: 1,
  };
  const myArrayObj = {
    settings: mySettingObject,
    array: [{ test: 1 }, { test: 2 }, { test: 3 }],
  };
  const myFileName = 'test';
  const blob = new Blob([JSON.stringify(myArrayObj)], {
    type: 'application/json',
  });
  this.saveAs(blob, `${myFileName}.json`);
}

saveAs(blob: any, filename: any) {
  const url = window.URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = filename;
  a.click();
  window.URL.revokeObjectURL(url);
}

On upload we use the FileReader, readAsText to read in UTF-8 format. Finally, we again re-access these properties using the same property names.

onSelectFile(event: any) {
  this.selectedFile = event.target.files[0];
  const fileReader = new FileReader();
  fileReader.readAsText(this.selectedFile, 'UTF-8');
  fileReader.onload = () => {
    const data = JSON.parse(<string>fileReader.result);
    console.log('settings', data.settings);
    console.log('settings', data.array);
  };
  fileReader.onerror = (error) => {
    console.log(error);
  };
}

Full Code:

import { Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';

@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <button (click)="downloadFile()">download</button>
    <hr/>
    <input type='file' (change)="onSelectFile($event)">
  `,
})
export class App {
  name = 'Angular';
  selectedFile: any;

    downloadFile() {
      const mySettingObject = {
        qwerty: 1,
      };
      const myArrayObj = {
        settings: mySettingObject,
        array: [{ test: 1 }, { test: 2 }, { test: 3 }],
      };
      const myFileName = 'test';
      const blob = new Blob([JSON.stringify(myArrayObj)], {
        type: 'application/json',
      });
      this.saveAs(blob, `${myFileName}.json`);
    }

    saveAs(blob: any, filename: any) {
      const url = window.URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = filename;
      a.click();
      window.URL.revokeObjectURL(url);
    }

    onSelectFile(event: any) {
      this.selectedFile = event.target.files[0];
      const fileReader = new FileReader();
      fileReader.readAsText(this.selectedFile, 'UTF-8');
      fileReader.onload = () => {
        const data = JSON.parse(<string>fileReader.result);
        console.log('settings', data.settings);
        console.log('settings', data.array);
      };
      fileReader.onerror = (error) => {
        console.log(error);
      };
    }
}

bootstrapApplication(App);

Stackblitz Demo

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.