'What is the difference between valueChanges and snapshotChanges()

this is my component.html

<div class="form-group">
        <label for="category">Category</label>
        <select ngModel name="category" id="category" class="form-control">
            <option value=""></option>
            <option *ngFor="let c of categories$ | async" [value]="c.key$">
                {{ c.name }}
            </option>    
        </select>
     </div>

This is my Component.ts

categories$: Observable<any[]>;

  constructor(categoryService: CategoryService) { 
    this.categories$ = categoryService.getCategories();
  }


  save(product){
    console.log(product);
  }

This is my categoty.service.ts I used both valueChanges() and snapShotChanges(). In using valueChanges i can access c.name but cannot c.key And using snapshotChanges() i can access c.key but cannot access c.name

getCategories(){
    //return this.db.list('/categories/').valueChanges();
    return this.db.list('/categories').snapshotChanges();`
  }

I need to access c.name and c.key$ in the same time Need a solution for this



Solution 1:[1]

valueChanges():

Use it when you just need the object data. No document metadata is attached which makes it simple to render to a view.

snapshotChanges():

When you need the document data but also want to keep around metadata. This metadata provides you the underyling DocumentReference and document id. Having the document's id around makes it easier to use data manipulation methods. This method gives you more horsepower with other Angular integrations such as ngrx, forms, and animations due to the type property. The type property on each DocumentChangeAction is useful for ngrx reducers, form states, and animation states.

Basically snapshotChanges() will give you access to the document id compared to valueChanges()

https://github.com/angular/angularfire/blob/master/docs/firestore/documents.md

Solution 2:[2]

By adding .pipe(tap(categories => console.log(categories)); to .snapshotChanges() you get a good look on what the data you're working with is looking like. It's a collection of objects that look like below

0: {
  payload: DataSnapshot,
  type: "value",
  prevKey: null,
  key: "frock"
},
1: {
  payload: DataSnapshot,
  type: "value",
  prevKey: "frock",
  key: "saree"
},

As you can see, there's no name property in your data, so you can't use that. You must instead use one of the other values that the data provides, such as key or prevKey.

On another note, I don't think it's a good idea to use snapshotChanges to map data to a select dropdown. I'm sure there are better ways in Firestore to retrieve the values.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Peter Haddad
Solution 2 Daniel B