Search code examples
javascriptangulartypescriptgoogle-cloud-firestoreangularfire2

AngularFire2 update creates new document field instead of updating a field


I would like to update a Firestore model containing a profile name and a list of hashtags with Angular 6. The "name" is stored as the value of a document field and the "hashtags" are stored as the keys of an object. When I try to update the database entry, my program adds a new document field called "data" every time I call the update function instead of updating the existing fields.

How can I fix this?

This is how my firestore looks like before the update. How the database looks before the update

My update function adds a new "data" field instead of updating everytime I call it. enter image description here

My Firestore Service:

export class MembersService {
  membersCollection: AngularFirestoreCollection<Member>;
  members$: Observable<Member[]>;
  memberDoc: AngularFirestoreDocument<Member>;

  constructor(public afs: AngularFirestore) {
    this.membersCollection = afs.collection<Member>('Members');
    this.members$ = this.membersCollection.snapshotChanges().pipe(
      map(actions => actions.map(a => {
        const data = a.payload.doc.data() as Member;
        const id = a.payload.doc.id;
        return { data, id };
      }))
    );
  }

   getMembers(): Observable<Member[]> {
     return this.members$;
   }

   updateMember(member: Member) {
    this.memberDoc = this.afs.doc(`Members/${member.id}`);
    this.memberDoc.update(member);
   }
}

My input component.ts:

export class MembersComponent implements OnInit {
  members: Member[];
  editState: boolean;
  membertoEdit: Member;

  constructor(private membersService: MembersService) {
    this.editState = false;
   }

  ngOnInit() {
    this.membersService.getMembers().subscribe(members => {
      this.members = members;
    });
  }

  editMember(member: Member) {
    this.editState = true;
    this.membertoEdit = member;
  }

  clearState() {
    this.editState = false;
    this.membertoEdit = null;
  }

  submit(member: Member, editName: string, editHashtag: string) {
    if ( editName !== '' && editHashtag !== '') {
      this.membertoEdit.name = editName;
      const key = editHashtag;
      const object = {};
      object[key] = true;
      this.membertoEdit.hashtag = object;
      this.membersService.updateMember(this.membertoEdit);
    }
    this.clearState();
  }
}

My component.html for the user Input:

<button *ngIf="editState == false" (click)="editMember(member)">edit</button>

<div *ngIf="editState && membertoEdit.id == member.id">
  <form>
      <input type="text"  #editName>
      <input type="text" #editHashtag>
      <button (click)="submit(member, editName.value, editHashtag.value);
        editName.value=''">Submit</button>
    </form>>
</div>


Solution

  • Found a solution: Even I don´t think it is elegant. It´s possible to pass every input on its own

    updateMember(member: Member, editName: string, editHashtag: object) {
        this.memberDoc = this.afs.doc(`Members/${member.id}`);
        console.log(this.memberDoc);
        this.memberDoc.update({
          name: editName,
          hashtag: editHashtag
        });
       }

    submit(member: Member, editName: string, editHashtag: string) {
        if ( editName !== '' && editHashtag !== '') {
          const key = editHashtag;
          const object = {};
          object[key] = true;
          this.membersService.updateMember(member, editName, object);
        }
        this.clearState();
      }