8

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.

5 Answers 5

24

I used typescript spread operator

  add(wizard: Wizard): Promise<DocumentReference> {
    return this.wizardCollection.add({...wizard});
  }
Sign up to request clarification or add additional context in comments.

Comments

8

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.

1 Comment

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

I used

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

3 Comments

this worked for me as well.. no clue why have to stringify the object .. :(
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.
This is a bad idea as it will destroy any timestamps or GeoPoints in the process
1

The below code worked for me in your Product.component.ts file

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');
}

save() {
    const productData ={};
       
      productData['code']:'123',
      productData['desc']:'yes',
      productData['stock']:500,
      productData['price']:10000,
      productData['off']:10
  
    this.productsRef.add(productData).then( _ => alert(this.successMsg));
}

Comments

0

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)); }

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.