Search code examples
angularjsfirebaseangularangularfireangular2-services

How to send more than just one value to Firebase


I have been using https://github.com/rolandjitsu/ng2-lab to experiment with.

My problem is that I want to have the name and amount for each shirt as can be seen in my Service, but when I try call

add(name: string, amount: string) in the Service

or

add() { this.shirts.add(this.form.name, this.form.amount); in the Component

I get an error like this:

src/app/services/shirts.ts(11,14): error TS2415: Class 'Shirts' incorrectly extends base class 'FirebaseArray'.
  Types of property 'add' are incompatible.
    Type '(name: string, amount: string) => Promise<Firebase>' is not assignable to type '(data: any) => Promise<Firebase>'.

It works if I just add the Name like this: add(name: string) but I would like to be able to add the whole schema not just the name value.

I realise I am probably doing something very basic wrong but and I think I have got that I can't add 2 parameters to theadd() function but I don't know how to then add all the data.

services/shirts.ts

import {FirebaseArray, FirebaseArrayValue} from '../common/firebase_array';

export interface Shirt extends FirebaseArrayValue {
  createdAt: number | string;
  updatedAt: number | string;
  name: string;
  amount: string;
}

export class Shirts extends FirebaseArray {
  add(name: string, amount: string): Promise<Firebase> { // I can't add amount here, I get an error.
    return super.add(<Shirt>{
      createdAt: Firebase.ServerValue.TIMESTAMP,
      updatedAt: Firebase.ServerValue.TIMESTAMP,
      name: name,
      amount: amount // This Doesn't seem to work
    });
  }
}

ShirtComponent

class Form {
  name: string;
  amount: string;
}

@Component({
  moduleId: module.id,
  selector: 'shirt',
  encapsulation: ViewEncapsulation.Emulated,
  templateUrl: './shirt_component.html',
  styleUrls: ['./shirt_component.css'],
  directives: [
    CORE_DIRECTIVES,
    FORM_DIRECTIVES,
    ROUTER_DIRECTIVES,
    ShirtListComponent
  ]
})

export class ShirtComponent {
  form: Form = new Form();
  private _shirts: Shirts;
  constructor(@Inject(Shirts) csp: Promise<Shirts>, _client: AuthClient) {
    csp.then((cs) => this.shirts = cs);
    this._client = _client;
  }
  add() {
    this.shirts.add(this.form.name, this.form.amount); // I don't know how to load all my data here it seems to work with only one parameter "this.form.name"
    this.form.name = '';
    this.form.amount = '';
    return false;
  }
}

ShirtComponent.html Form

<form class="text-center" #shirt="ngForm" (ngSubmit)="add()" novalidate>

  <fieldset class="form-group">
    <label for="name" class="sr-only">Name/Title</label>
    <input type="text" class="form-control" id="name" name="name" ngControl="name" [(ngModel)]="form.name" placeholder="Name/Title" autocomplete="off" required>
  </fieldset>

  <fieldset class="form-group">
    <label for="amount" class="sr-only">Amount</label>
    <input type="number" class="form-control" id="amount" name="amount" ngControl="amount" [(ngModel)]="form.amount" placeholder="Amount" autocomplete="off" required>
  </fieldset>

  <button type="submit" [disabled]="!shirt.form.valid">
    <glyph src="assets/glyphs/plus.svg"></glyph>
  </button>
</form>

EDIT:

This is what the add() function in firebase_array.ts looks like, perhaps it's part of what I am missing?

/**
     * Adds a record to Firebase and returns the reference in a promise.
     * To obtain its key, use `ref.key()`, assuming `ref` is the variable assigned to the return value.
     *
     * Note that all the records stored in the array are objects.
     * Primitive values get stored as `{ value: primitive }`.
     * Moreover, each record will get a new property `key` which is used to do changes to the record (most methods require the `key`).
     *
     * @name add
     * @memberof FirebaseArray
     *
     * @param {*} data - Data to add to the array (and sync with Firebase).
     * @returns {Promise<Firebase>} A promise with a Firebase reference to the data.
     */

    add(data: any): Promise<Firebase> {
        return new Promise((resolve, reject) => {
            let key: string = this.ref.push().key();
            let ref: Firebase = this.ref.child(key);
            ref.set(transformDataToFirebaseArrayValue(data), (error) => {
                if (error) reject(error);
                else resolve(ref);
            });
        });
    }

Solution

  • Seems to be a limitation of TypeScript what is allowed for methods overridden in subclasses. The error message indicates that the overridden method needs a signature compatible with the method in the subclass, which is reasonable. Create instaead a method with a different name

    export class Shirts extends FirebaseArray { add(name: string, amount: string): Promise { // I can't add amount here, I get an error.

    export class Shirts extends FirebaseArray {
      addShirt(name: string, amount: string): Promise<Firebase> {
        return super.add(<Shirt>{
          createdAt: Firebase.ServerValue.TIMESTAMP,
          updatedAt: Firebase.ServerValue.TIMESTAMP,
          name: name,
          amount: amount // This Doesn't seem to work
        });
      }
    }