By Marcelo J Forclaz


2017-11-04 12:47:40 8 Comments

First of all I have to say that I'm learning Angular. Maybe the answer is too evident but I can't see it. I've searched responses for similar questions in the web but I didn't found any that works for me.

I made an Angular Template Driven Form to store products on my Firebase Cloud Firestore Database. I created a model called "Product"

product.ts

export class Product {
constructor(
    public code: string,
    public desc: string,
    public stock: number,
    public price: number,
    public off: number,
    public details?: string
) {}

}

Then, I have the product.component.ts

import { Component } from '@angular/core';
import { Product } from './product';
import { AngularFirestore, AngularFirestoreCollection } from 'angularfire2/firestore';
import { Observable } from 'rxjs/Observable';


@Component({
    selector: 'app-admin-product',
    templateUrl: 'product.component.html'
})

export class AdminProductComponent {

model = new Product('', '', 0, 0, 0);
successMsg = 'Data successfully saved.';

productsRef: AngularFirestoreCollection<Product>;
product: Observable<Product[]>;

constructor(private afs: AngularFirestore) {
    this.productsRef = this.afs.collection<Product>('productos');
}

save() {
    this.productsRef.add(this.model).then( _ => alert(this.successMsg));
}

TypeScript doesn't return errors at all and everything seems to be ok. But when I run my app and try to save the form's data, console returns next error:

AdminProductComponent.html:51 ERROR Error: Function CollectionReference.add() requires its first argument to be of type object, but it was: a custom Product object

I solved it passing the custom object to a simple object like this:

const product = {
    code: this.model.code,
    desc: this.model.desc,
    stock: this.model.stock,
    price: this.model.price,
    off: this.model.off,
    details: this.model.details
}

And saving data like this:

save() {
    this.productsRef.add(product).then( _ => alert(this.successMsg)); }

But I think that it isn't the properly solution, maybe could cause future issues scalling the app.

4 comments

@Jan Krajewski 2020-05-17 22:26:34

You can also create a deep copy method within the Product class, but this is less elegant.

export class Product {
  constructor(
    public code: string,
    public desc: string,
    public stock: number,
    public price: number,
    public off: number,
    public details?: string
  ) {}

  public getData(): object {
    const result = {};
    Object.keys(this).map((key) => (result[key] = this[key]));
    return result;
  }
}

And then use it as:

this.productsRef.add(product.getData()).then( _ => alert(this.successMsg)); }

@Rodger Gutierrez 2019-01-01 23:29:44

I used

save() {
    const param = JSON.parse(JSON.stringify(this.model));
    this.productsRef.add(param).then( _ => alert(this.successMsg));
 }

@Kod 2019-07-07 04:05:10

this worked for me as well.. no clue why have to stringify the object .. :(

@Craig Shearer 2019-09-16 03:30:51

Using JSON.stringify turns the custom object into a string. JSON.parse parses the JSON and returns an object. Since the JSON doesn't (and can't) have any type information a plain object is returned.

@Chris 2020-05-12 07:53:59

This is a bad idea as it will destroy any timestamps or GeoPoints in the process

@peterbrown 2018-03-22 17:56:47

I used typescript spread operator

  add(wizard: Wizard): Promise<DocumentReference> {
    return this.wizardCollection.add({...wizard});
  }

@Hareesh 2017-11-04 13:04:27

You can try this way, hope you are using latest typescript

product.ts

export interface Product {
   code: string;
   desc: string;
   stock: number;
   price: number;
   off: number;
   details?: string
}

in your product.component.ts

export class AdminProductComponent {

model:Product;
successMsg = 'Data successfully saved.';

productsRef: AngularFirestoreCollection<Product>;
product: Observable<Product[]>;

constructor(private afs: AngularFirestore) {
    this.productsRef = this.afs.collection<Product>('productos');

    this.model = {
      code:'',
      desc:'',
      stock:0,
      price:0,
      off:0
    }
}

save() {
    this.productsRef.add(this.model).then( _ => alert(this.successMsg));
}

I think by doing this model = new Product('', '', 0, 0, 0); you get an instance of the class not the object.

@Marcelo J Forclaz 2017-11-04 13:14:06

Thanks @Hareesh ! I've just remove the "public" of every Product interface index and separated with coma instead of semicolon and works fine!

Related Questions

Sponsored Content

20 Answered Questions

[SOLVED] Angular HTML binding

3 Answered Questions

[SOLVED] What is Firebase Firestore 'Reference' data type good for?

15 Answered Questions

[SOLVED] Cloud Firestore collection count

2 Answered Questions

[SOLVED] firebase error on angular 6

1 Answered Questions

[SOLVED] Having trouble with Angular: argument of type

  • 2019-08-17 21:34:50
  • IDavidJr _
  • 112 View
  • 1 Score
  • 1 Answer
  • Tags:   angular typescript

2 Answered Questions

[SOLVED] How to have placeholder images with Angular 6 Firebase?

3 Answered Questions

1 Answered Questions

Not able to connect Firebase with Angular 2

Sponsored Content