How can I save a TypeScript object to Firebase using serialization?

Having an issue: Within my angular application, I have implemented a lot of classes with inheritance. However, upon attempting to save these objects to Firebase, I encountered an error indicating that I am trying to persist custom objects which is not supported.

Below is the error message:

ERROR FirebaseError: Function DocumentReference.set() called with invalid data (via `toFirestore()`). Unsupported field value: a custom object (found in field itinerary in document trips/iLK63UGEsYpZbn2NG2N7)
    at new n (http://localhost:8100/vendor.js:39963:23)
    at Gu (http://localhost:8100/vendor.js:53855:16)
    at t.i_ (http://localhost:8100/vendor.js:53575:16)
    at Mu (http://localhost:8100/vendor.js:53808:37)
    at Uu (http://localhost:8100/vendor.js:53692:50)
    at http://localhost:8100/vendor.js:53792:17
    at _ (http://localhost:8100/vendor.js:40153:68)
    at Cu (http://localhost:8100/vendor.js:53791:56)
    at Ru (http://localhost:8100/vendor.js:53616:19)
    at n.set (http://localhost:8100/vendor.js:55193:40)
defaultErrorLogger @ core.js:5980

How can these objects be serialized effectively?

I have some complex objects with useful helper methods and converting my model does not seem straightforward.

Provided below is the basic structure of the model:

export class Trip {
  id: string;
  owner: string;
  name: string;
  startDate: Date;
  endDate: Date | undefined;
  coverImageUrl: string;
  itinerary: Itinerary;

  constructor() {
    this.itinerary = new Itinerary();
  }
}

export class Itinerary {
  stats: ItineraryStats;
  steps: Step[];

  constructor() {
    this.steps = Step[0];
    this.stats = new ItineraryStats();
  }
}

export class ItineraryStats {
  duration: number;
  driveTime: number;
  driveDistance: number;

  averageDriveDistancePerDay(): number {
    return this.driveDistance / this.duration;
  }
  averageDriveTimePerDay(): number {
    return this.driveTime / this.duration;
  }
}


export abstract class Step {
  start: Date;
  end: Date;
  duration: number;
  enforcedStartStop: boolean;
  warning: string;
}
export abstract class StopStep extends Step {
  id: string;
  name: string;
  description: string;
  pointOfInterest: PointOfInterest | null;
  address: string;
  coordinates: firebase.firestore.GeoPoint;
}


export class ActivityStep extends StopStep {
  duration: number;

  constructor() {
    super();
    this.id = Guid.newGuid();
  }
}


export class NightStep extends StopStep {
  nightNumber: number;
  numberOfNight: number;
}

export class PointOfInterest {
  type: PointOfInterest;
}


export class TravelStep extends Step {
  Mode: TravelMode;
  PolyLines: string;
}

The goal is to save a Trip object here.

I am utilizing NGXS + AngularFire, although the error persists even when solely using AngularFire. I attempted using a library(classToPlain) for TypeScript to JSON conversion but encountered issues because certain objects needed to remain as Firebase objects rather than be transformed.

Answer №1

To maintain control over the complexity of your object in handling JSON data for Facebook messages, it is recommended to implement the toJSON and fromJSON methods within the Trip class. Utilizing JSON.stringify, as suggested by Ratul Sharker, will assist in managing the object structure effectively.

For further details, refer to this documentation link.

Update

An essential update involves incorporating a type property in the Step class along with a constructor to enforce setting the type for all subtypes. Additionally, a static method named CreateFromJS can be implemented to reconstruct a step object from raw JavaScript data:

(Updated TypeScript code snippets)

Furthermore, each Step subclass should have a constructor to define its specific type:

(Revised TypeScript code snippets)

In the Trip class, functions should be added to facilitate conversion to pure JS objects and restoration from them:

(Modified TypeScript code snippet)

Due to Firebase constraints on custom objects, transforming objects to pure JS before storage is necessary. Therefore, remember to call getJSObject when saving a Trip to Firebase and utilize the createFromJS static method while retrieving the stored object.

To validate the implementation, create a sample trip with multiple steps and test the new functionalities as outlined above.

Update 2

To eliminate the need for the type property in custom classes, you can adjust the getJSObject method in the Trip class:

(Further refined TypeScript code snippet)

By identifying the type of each step based on its class name and updating the corresponding property in the pure JS object, the previous approach can be optimized without relying on an explicit type property.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

When defining a class property in TypeScript, you can make it optional by not providing

Is there a way to make a property on a Class optional without it being undefined? In the following example, note that the Class constructor takes a type of itself (this is intentional) class Test { foo: number; bar: string; baz?: string; construc ...

When trying to access the "form" property of a form ElementRef, TypeScript throws an error

I've encountered an issue with accessing the validity of a form in my template: <form #heroForm="ngForm" (ngSubmit)="onSubmit()"> After adding it as a ViewChild in the controller: @ViewChild('heroForm') heroForm: ElementRef; Trying ...

Encountered an issue while trying to install the package '@angular/cli'

Encountered errors while attempting to install @angular/cli using npm install -g @angular/cli. The node and npm versions on my system are as follows: C:\WINDOWS\system32>node -v v 12.4.0 C:\WINDOWS\system32>npm -v 'C ...

How can I arrange selected options at the top in MUI autocomplete?

I am currently working with mui's useAutocomplete hook https://mui.com/material-ui/react-autocomplete/#useautocomplete Is there a way to programmatically sort options and place the selected option at the top using JavaScript sorting, without resorti ...

Angular Form Container

I am in the process of creating a wrapper for forms. Everything is functioning except for the validation aspect. The issue lies in the fact that my ngForm property does not include the controls from the ng-content. My objective is to have the ngSubmit Even ...

Error Alert: Redundant Identifier in Angular 2 TypeScript Documents

After following the Angular2 TS Quickstart guide, I noticed duplicate files scattered across various folders in my project. For browser: typings/browser node_modules/angular2/typings/browser Regarding es6-shim: node_modules/angular2/typings/es6-shi ...

Encountering an issue on Safari: WeakMap variable not found in .NET Core 1.1.0 and Angular 2 application

I recently deployed a .NET Core 1.1.0 + Angular 2 + Typescript app on ASPHostPortal and encountered an issue while accessing it from Safari. The console showed the following exception: Can't find variable:WeakMap This caused the site to not load p ...

The default selected item in Material Select does not function properly on the second attempt

Is there a way to reset an Angular Material Select Component to its default value after manually changing it on the UI screen? It seems to work fine during initialization but not after manual changes. I am attempting to create a button that will revert th ...

WebStorm provides alerts for objects, types, and directives within Angular, yet they function properly

Why is WebStorm displaying warnings for objects, types, and directives in Angular Template HTML even though they are functioning correctly? Despite the fact that all types and Angular directives in the HTML structure are working fine within Angular on Web ...

The validation of DOM nesting has detected that a <td> element cannot be placed within an <a> element

When working on a React project with Material UI, I encountered an issue while trying to create a table. My goal was to make the entire row clickable, directing users to a page with additional information on the subject. Below is the snippet of code for th ...

Reading JSON in Spring Boot can sometimes be challenging, especially when faced with errors like "Cannot deserialize value of type `X` from Array value." This error typically occurs when trying to parse an array value

I am facing an issue with sending data from my Angular application to SpringBoot. The problem arises when the server does not receive the correct object that is being sent. Upon checking the console.log output for what is being sent to the server, everyth ...

Tips for merging data gathered from an Observable with additional information from a secondary request

So I'm on a mission to enhance my knowledge by utilizing a service that fetches a list of Posts and then for each post, making another call to retrieve the associated comments. The data I'm working with can be found at https://jsonplaceholder.ty ...

Guide to establishing intricate conditions for TypeORM insertion

When attempting to insert data based on a specific condition, such as if shopId = "shopA", I want to include the shopdetail. In order to achieve this, I have implemented the following business logic, which is somewhat complex. Is there a more ef ...

Opening the Gmail app from a link using JavaScript

What is the best way to open the Gmail app from a hyperlink? This link opens WhatsApp <a href="https://wa.me/">whatsapp</a> <a href="mailto:<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="6a1f190f ...

What is the process for obtaining an app icon from the store using Angular?

Currently, I am working on an app using ionic, angular, and Cordova. Within this app, there are links to other apps available in the app store. My main query is: Is there a way to retrieve the icons of these apps from the store? I aim to display these ic ...

Uninitialized variables in Angular 4.0 causing Rxjs issues

Since the update to angular 4.0, I've been encountering errors with RxJs variables. While everything builds without any issues, when I try to load the page, I receive this error message: ERROR Error: Uncaught (in promise): TypeError: Cannot read pr ...

JavaScript: Transform an Array of Strings into an Array of Objects

Here is an array containing different strings: let myArray : ["AA","BB" , "CC" ...] My goal is to transform it into an array of objects: myArray = [{"id":1 , "value": "AAA"},{"id":2 , "value": "BBB"},{"id":3 , "value": "CCC"}...] I attempted to achiev ...

Utilize Typescript/Javascript to utilize the Gmail API for sending emails via email

I am trying to send emails from my application using my Gmail account with Ionic. I have followed tutorials from SitePoint and Google Developers. Here is how I'm initializing the client: client_id: gapiKeys.client_id, discoveryDocs: ["https://www.goo ...

Troubleshooting a problem with Angular2 involving the This.http.get function

Currently, I am delving into Angular 2 and have set up an ASP.NET WebApi locally hosted in IIS at http://localhost:8081/ping. The API call successfully returns a string serialized as a JSON Object. Below is the code for my service: import { Injectable } ...

Issue with Angular 4: Mega menu does not automatically close when a menu item is selected from within it

I am currently working on an Angular 4 project that includes a mega menu. My issue is that when I click on a menu within the mega menu, I want it to close. However, in my current setup, the menu always remains open even after clicking on a specific option. ...