Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does .map / .subscribe on Angular2 work?

I'm trying to fill 3 variables (arrays) from Firebase with AngularFire2.

DB structure is this:

Firebase3 structure

I'm stuck at how should I resolve Promise to map to fill those variables. Even easiest queries return nothing and also console.log doesn't show anything.

    let testConnection = this.AngularFire.database.list(DbPath)
          .map((items) => {
            console.log(items);
            return items.map(item => {
                console.log(items);
                 console.log(item);
   })})

I tried with .subscribe, but since this preserves snapshots (and without preserving it doesn't work), it's not doable for me :/. But it worked and filled it right.

return this.AngularFire.database.list(DbPath, { preserveSnapshot: true })
.subscribe(
(snapshots:any) => {
    snapshots.forEach(snapshot => {
    console.log(snapshot.key);

       if (snapshot.key === 'disliked') {
       this.dataListDisliked = snapshot.val();
   }
   ...

Any ideas? Thanks a lot

like image 342
Kuba Chour Avatar asked Oct 13 '16 20:10

Kuba Chour


1 Answers

I hope that I can answer your question, because I don't know if I understand it correctly.

So this piece of code:

let testConnection = this.AngularFire.database.list(DbPath)
  .map((items) => { //first map
    console.log(items);
    return items.map(item => { //second map
      console.log(items);
      console.log(item);
    })
  })

I'm going to try to break it down for you, Angular Firebase uses observables, so when you create a list object it returns an Observable. So your first map is a function from observables, it allows you to map a function for each time a observable emits a value. So basically your first map will run every time your list has changed. Look at this list of Todos: enter image description here

Now this is a very simple app component:

import { Component } from '@angular/core';
import { AngularFire, FirebaseListObservable } from 'angularfire2';
import 'rxjs/add/operator/map'; // you might need to import this, or not depends on your setup

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app works!';
  text = '';
  todos: FirebaseListObservable<any[]>;
  constructor(af: AngularFire) {
    this.todos = <FirebaseListObservable<any>> af.database.list('Todos').map(items => { //first map
          return items.map(item => { //second map
            item.text = item.text.toUpperCase();
            return item;
          })
        });
  }

  addTodo() {
    this.todos.push({
      text: this.text,
      completed: false
    });
    this.text = '';
  }

  changeTodo(key: string, completed){
    this.todos.update(key, {completed: !completed});
  }
}

The code is very simple, the only thing that might be confusing is this line:

<FirebaseListObservable<any>> af.database.list('Todos').map(items 

You can read more about that in this answer

Now if you run our app as it is, nothing will happen. Nothing will be logged into our console. Why? Well because nothing has subscribed to our Todos observable. How do we subscribe? We have two ways, using the async pipe on our views:

<li *ngFor="let todo of todos | async" [ngClass]="{completed: todo.completed}" (click)="changeTodo(todo.$key, todo.completed)">
    {{ todo.text }}
  </li>

Or subscribing manually to our Observable on our component:

this.todos.subscribe(todos => {
  //now we can assign our todos to a variable
  this.ourTodoList = todos;
});

I created a simple Github repo with this very basic Todo App, if you want you can clone it, point to your Firebase database (all the instructions are on the README file) and run on your localmachine.

This is how the app looks: enter image description here

like image 173
Fabio Antunes Avatar answered Oct 13 '22 02:10

Fabio Antunes