Categories
Vue

Using Firebase in a Vue App Vuefire and Vuexfire

The Vuefire library lets us add Firebase database manipulation capabilities right from our Vue app.

In this article, we’ll look at how to use Vuefire and Vuexfire to add support for Cloud Firestore database manipulation into our Vue app.

Geopoints

We can add the latitude and longitude of a location with the GeoPoint constructor.

This is only supported with the CloudFirestore.

For example, we can write:

<template>
  <div>
    <button @click="add">add city</button>
    <div v-for="c of cities" :key="c.id">{{c}}</div>
  </div>
</template>
<script>
import { db, GeoPoint } from "./db";
export default {
  data() {
    return {
      cities: []
    };
  },
  mounted() {
    this.$bind("cities", db.collection("cities"));
  },
  methods: {
    async add() {
      await db.collection("cities").add({
        name: "London",
        location: new GeoPoint(51.3, 0)
      });
    }
  }
};
</script>

db.js

import firebase from "firebase/app";
import "firebase/firestore";
export const db = firebase
  .initializeApp({ projectId: "project-id" })
  .firestore();
const { Timestamp, GeoPoint } = firebase.firestore;
export { Timestamp, GeoPoint };

We called the add method with a GeoPoint instance to save the latitude and longitude of a location.

Then we should get something like:

{ "name": "London", "location": { "latitude": 51.3, "longitude": 0 } }

saved.

Timestamps

Also, we can save timestamps with Vuefire.

We use the Timestamp.fromDate method to create our timestamp.

For example, we can write:

<template>
  <div>
    <button @click="add">add event</button>
    <div v-for="e of events" :key="e.id">{{e}}</div>
  </div>
</template>
<script>
import { db, Timestamp } from "./db";
export default {
  data() {
    return {
      events: []
    };
  },
  mounted() {
    this.$bind("events", db.collection("events"));
  },
  methods: {
    async add() {
      await db.collection("events").add({
        name: "event",
        date: Timestamp.fromDate(new Date("2029-07-14"))
      });
    }
  }
};
</script>

We passed in a Date instance to Timestamp.fromDate .

Then we get something like:

{ "name": "event", "date": { "seconds": 1878681600, "nanoseconds": 0 } }

saved as a result.

Vuefire

We can use Vuefire to get and set data from Firebase database and store the database’s state in our Vuex store.

To use it, we install the required packages by running:

yarn add vuex vuexfire vuefire firebase

or

npm i vuex vuexfire vuefire firebase

Now we can create our Vuex store and bind our store to the Firebase database by writing:

main.js

import Vue from "vue";
import App from "./App.vue";
import { firestorePlugin } from "vuefire";
import { vuexfireMutations, firestoreAction } from "vuexfire";
import Vuex from "vuex";
import { db } from "./db";

Vue.use(Vuex);
Vue.use(firestorePlugin);
Vue.config.productionTip = false;

const store = new Vuex.Store({
  state: {
    books: []
  },
  mutations: {
    ...vuexfireMutations
  },
  actions: {
    bindBooksRef: firestoreAction((context) => {
      return context.bindFirestoreRef("books", db.collection("books"));
    })
  },
  getters: {
    books: (state) => {
      return state.books;
    }
  }
});

new Vue({
  store,
  render: (h) => h(App)
}).$mount("#app");

App.vue

<template>
  <div>{{books}}</div>
</template>
<script>
import { mapGetters, mapActions } from "vuex";

export default {
  data() {
    return {};
  },
  methods: {
    ...mapActions(["bindBooksRef"])
  },
  computed: {
    ...mapGetters(["books"])
  },
  mounted() {
    this.bindBooksRef();
  }
};
</script>

We create our store with the Vuex.Store constructor as usual.

But we import the vuefireMutations and put it in our store.

Also, our actions are created with the fireStoreAction function.

And we call the context.bindFirestoreRef method to get our store data and set it as the state.

The first argument is the state name, and the 2nd is the collection we want to bind to the state with the given name.

Also, we have a getter to get the books state.

In App.vue , we map the actions and getters to methods and computed properties respectively.

After we done that, we can call this.bindBooksRef action which we mapped to a method to populate the books state.

Then our template should show the books data.

Conclusion

We can add geolocation and timestamp data with Vuefire.

Also, the Vuexfire library lets us bind the Firebase database to our Vuex store easily.

Categories
Vue

Using Firebase in a Vue App Vuefire — Adding and Removing Documents

The Vuefire library lets us add Firebase database manipulation capabilities right from our Vue app.

In this article, we’ll look at how to use Vuefire to add support for Cloud Firestore database manipulation into our Vue app.

Removing a Document

Vuefire lets us remove a document with the remove or delete method.

For example, we can write:

db.js

import firebase from "firebase/app";
import "firebase/firestore";
export const db = firebase
  .initializeApp({ projectId: "project-id" })
  .firestore();
const { Timestamp, GeoPoint } = firebase.firestore;
export { Timestamp, GeoPoint };

App.vue

<template>
  <div>
    <div v-for="b of books" :key="b.id">{{b}}</div>
    <button @click="remove">remove book</button>
  </div>
</template>
<script>
import { db } from "./db";
export default {
  data() {
    return {
      books: [],
      bookId: "Cbk7fgYR75xRFkiqq5Qw"
    };
  },
  mounted() {
    this.$bind("books", db.collection("books"));
  },
  methods: {
    remove() {
      db.collection("books")
        .doc(this.bookId)
        .delete();
    }
  }
};
</script>

to remove the books document with ID Cbk7fgYR75xRFkiqq5Qw .

We can also use the this.$firestoreRefs property to access the document we want to delete.

For instance, we can write:

<template>
  <div>
    <div v-for="b of books" :key="b.id">{{b}}</div>
    <button @click="remove">remove book</button>
  </div>
</template>
<script>
import { db } from "./db";
export default {
  data() {
    return {
      books: [],
      bookId: "pejGvWmS7NMKTRtqXg9z"
    };
  },
  mounted() {
    this.$bind("books", db.collection("books"));
  },
  methods: {
    remove() {
      this.$firestoreRefs.books.doc(this.bookId).delete();
    }
  }
};
</script>

The doc method gets the item with the given ID.

Adding Documents to a Collection

We can add documents to a collection with the add method.

For example, we can write:

<template>
  <div>
    <button @click="add">add book</button>
    <div v-for="b of books" :key="b.id">{{b}}</div>
  </div>
</template>
<script>
import { db } from "./db";
export default {
  data() {
    return {
      books: []
    };
  },
  mounted() {
    this.$bind("books", db.collection("books"));
  },
  methods: {
    add() {
      db.collection("books").add({
        title: "new book"
      });
    }
  }
};
</script>

to add a new document to the books collection.

We can also use the this.$firestoreRefs property to access the collections we bound to our component and call add on it:

<template>
  <div>
    <button @click="add">add book</button>
    <div v-for="b of books" :key="b.id">{{b}}</div>
  </div>
</template>
<script>
import { db } from "./db";
export default {
  data() {
    return {
      books: []
    };
  },
  mounted() {
    this.$bind("books", db.collection("books"));
  },
  methods: {
    add() {
      this.$firestoreRefs.books.add({
        title: "new book"
      });
    }
  }
};
</script>

This will also add a new document to books .

References

We can reference a document in another document.

This is only available when we save data to a Cloud Firestore.

To do that, we just get the document and add it as part of the object we want to save:

<template>
  <div>
    <button @click="add">add book</button>
    <div v-for="b of books" :key="b.id">{{b}}</div>
  </div>
</template>
<script>
import { db } from "./db";
export default {
  data() {
    return {
      books: []
    };
  },
  mounted() {
    this.$bind("books", db.collection("books"));
  },
  methods: {
    add() {
      db.collection("books").add({
        name: "some book",
        author: db.collection("authors").doc("james-smith")
      });
    }
  }
};
</script>

We reference an author document in a new book entry by setting it as the value of a property.

Conclusion

We can add and remove documents easily with Vuefire and Firebase.

Documents can reference other documents.

Categories
Vue

Using Firebase in a Vue App Vuefire — Sorting, Filtering, and Updating

The Vuefire library lets us add Firebase database manipulation capabilities right from our Vue app.

In this article, we’ll look at how to use Vuefire to add support for Cloud Firestore database manipulation into our Vue app.

Sorting

We can sort the documents we’re querying with the orderBy method.

For example, we can write:

<template>
  <div>
    <div v-for="b of books" :key="b.id">{{b}}</div>
  </div>
</template>
<script>
import { db } from "./db";
export default {
  data() {
    return {
      books: []
    };
  },
  firestore: {
    books: db.collection("books").orderBy("title")
  }
};
</script>

db.js

import firebase from "firebase/app";
import "firebase/firestore";
export const db = firebase
  .initializeApp({ projectId: "project-id" })
  .firestore();
const { Timestamp, GeoPoint } = firebase.firestore;
export { Timestamp, GeoPoint };

We just call the orderBy with the key that we want to sort by to sort the query results.

Also, we can sort results returned by this.$bind :

<template>
  <div>
    <div v-for="b of books" :key="b.id">{{b}}</div>
  </div>
</template>
<script>
import { db } from "./db";
export default {
  data() {
    return {
      books: []
    };
  },
  mounted() {
    this.$bind("books", db.collection("books").orderBy("title"));
  }
};
</script>

Filtering Results

We can filter results with the where method.

For example, we can write:

<template>
  <div>
    <div v-for="b of books" :key="b.id">{{b}}</div>
  </div>
</template>
<script>
import { db } from "./db";
export default {
  data() {
    return {
      books: []
    };
  },
  mounted() {
    this.$bind(
      "books",
      db
        .collection("books")
        .where("wordCount", ">", 200)
        .orderBy("wordCount")
    );
  }
};
</script>

to get all the books entries that have wordCount bigger than 200.

Writing to the Database

We can use the Firebase SDK to write data to the database.

For example, if we want to update an existing entry, we can write:

<template>
  <div>
    <div v-for="b of books" :key="b.id">{{b}}</div>
    <button @click="update">update book</button>
  </div>
</template>
<script>
import { db } from "./db";
export default {
  data() {
    return {
      books: []
    };
  },
  mounted() {
    this.$bind("books", db.collection("books"));
  },
  methods: {
    update() {
      const [book] = this.books;
      const bookCopy = { ...book, title: "baz" };
      db.collection("books")
        .doc(book.id)
        .set(bookCopy)
        .then(() => {
          console.log("book updated");
        });
    }
  }
};
</script>

We added the update method to update our book.

In the method, we get the books entry that we want to update.

Then we make a copy of it and add the data we want to it.

And then we get the document we want to update to bookCopy with with the doc method.

The set method sets the document to the new content.

Then the then callback is called after the update is done.

Also, we can use the this.$fireStoreRefs method to get the document we want and update it.

For example, we can write:

<template>
  <div>
    <div v-for="b of books" :key="b.id">{{b}}</div>
    <button @click="update">update book</button>
  </div>
</template>
<script>
import { db } from "./db";
export default {
  data() {
    return {
      book: {},
      books: []
    };
  },
  mounted() {
    this.$bind("book", db.collection("books").doc("Cbk7fgYR75xRFkiqq5Qw"));
    this.$bind("books", db.collection("books"));
  },
  methods: {
    update() {
      this.$firestoreRefs.book.update({ title: "qux" }).then(() => {
        console.log("book updated!");
      });
    }
  }
};
</script>

We bound the this.book state to a document with in the books collection.

Then in the update method, we called this.$firestoreRefs.book.update to update book entry with the given ID with the new title value.

And then this should show in the template.

Conclusion

We can sort, filter, and update collections and documents in our Firebase database with Vuefire.

Categories
Vue

Using Firebase in a Vue App Vuefire — References and Querying

The Vuefire library lets us add Firebase database manipulation capabilities right from our Vue app.

In this article, we’ll look at how to use Vuefire to add support for Cloud Firestore database manipulation into our Vue app.

References to Other Documents

We can store references to other documents by referencing them.

This only works with the Cloud Firestore.

For example, we can write:

App.vue

<template>
  <div>
    <div v-for="c of cities" :key="c.id">{{c}}</div>
  </div>
</template>
<script>
import { db } from "./db";
const books = db.collection("books");
export default {
  data() {
    return {
      cities: []
    };
  },
  firestore: {
    cities: db.collection("cities")
  },
  async mounted() {
    await db.collection("cities").add({
      name: "London",
      books: [books.doc("1")]
    });
  }
};
</script>

db.js

import firebase from "firebase/app";
import "firebase/firestore";
export const db = firebase
  .initializeApp({ projectId: "project-id" })
  .firestore();
const { Timestamp, GeoPoint } = firebase.firestore;
export { Timestamp, GeoPoint };

We just reference the documents we want in an array to make a reference to them.

Then we can see the document wherever we reference it.

Unbinding or Unsubscribing to Changes

We can unbind any references to a collection by using the this.$unbind method.

We just have to pass in the collection name to the method:

this.$unbind('book')

Vuefire will reset the property by default.

So if we have:

this.$unbind('book')

or

this.$unbind('book', true)

then the this.book value will be reset to null .

If we have:

this.$unbind('book', false)

Then this.book will keep whatever value it has before.

We can also reset it to the value we want by passing in a function that returns the value we want to reset to:

this.$unbind('book', () => ({ title: 'foo' }))

If we reset a collection, then the value it’s bound to will be reset to an empty array.

So if we have:

this.$unbind('books')

then this.books will be [] after it’s been reset if books is bound to this.books .

We can also change the value when we call this.$bind :

await this.$bind('user', userRef)
this.$bind('user', otherUserRef, { reset: false })

They let us bind to the value we want.

Querying the Database

We can query the database with Vuefire.

For example, we can write:

<template>
  <div>
    <div v-for="b of books" :key="b.id">{{b}}</div>
  </div>
</template>
<script>
import { db } from "./db";
export default {
  data() {
    return {
      books: []
    };
  },
  mounted() {
    db.collection("books")
      .get()
      .then(querySnapshot => {
        const books = querySnapshot.docs.map(doc => doc.data());
        this.books = books;
      });
  }
};
</script>

We called the db.collection method to get the collection.

The get method gets the query results snapshot.

And then docs.map map the snapshot to data that we can use in our component.

In the template, we loop through the entries.

We can also query a single document by ID by using the doc method:

<template>
  <div>{{book}}</div>
</template>
<script>
import { db } from "./db";
export default {
  data() {
    return {
      book: {}
    };
  },
  mounted() {
    db.collection("books")
      .doc("UGRbRLiAzIl2efo1tmVP")
      .get()
      .then(snapshot => {
        const book = snapshot.data();
        this.book = book;
      });
  }
};
</script>

Where UGRbRLiAzIl2efo1tmVP is the ID of the document we’re looking for.

snapshot.data() returns the JavaScript object for the document.

Conclusion

We can save references to other documents in our app.

Also, we can unsubscribe to changes manually for a collection.

And there’re several ways to query a database with Vuefire.

Categories
Vue

Using Firebase in a Vue App Vuefire — Saving Data

The Vuefire library lets us add Firebase database manipulation capabilities right from our Vue app.

In this article, we’ll look at how to use Vuefire to add support for Cloud Firestore database manipulation into our Vue app.

Getting Data

We can get data in various ways with Vuefire.

We can call the this.$bind method with a collection.

For example, we can write:

Book.vue

<template>
  <div>{{book.title}}</div>
</template>

<script>
import { db } from "./db";
const books = db.collection("books");

export default {
  props: ["id"],
  data() {
    return {
      book: {}
    };
  },

  watch: {
    id: {
      immediate: true,
      async handler(id) {
        const book = await this.$bind("book", books.doc(id));
        console.log(book);
      }
    }
  }
};
</script>

db.js

import firebase from "firebase/app";
import "firebase/firestore";

export const db = firebase
  .initializeApp({ projectId: "project-id" })
  .firestore();

const { Timestamp, GeoPoint } = firebase.firestore;
export { Timestamp, GeoPoint };

We make the watcher for the id prop async so that we can use await to get the resolved value from this.$bind .

this.$bind returns a promise so we can do that.

book has the resolved value from the Cloud Firestore.

We can do the same for collections.

For example, we can write:

App.vue

<template>
  <div id="app">{{book.title}}</div>
</template>

<script>
import { db } from "./db";
const books = db.collection("books");

export default {
  name: "App",
  data() {
    return {
      title: "title",
      book: {}
    };
  },

  async mounted() {
    const [book] = await this.$bind(
      "books",
      books.where("title", "==", this.title)
    );
    this.book = book;
    console.log(book);
  }
};
</script>

We call the where method to search for an entry with the title instead of getting a document by ID.

The resolved value is destructured so that we can get the entry and display it in the template.

.key / id

The id property of a document isn’t enuerable.

So Object.keys won’t include the key in the array of keys.

But we can access it with the id property directly.

For example, we can write:

<template>
  <div id="app">
    <div v-for="b of books" :key="b.id">{{b.id}} - {{b.title}}</div>
  </div>
</template>

<script>
import { db } from "./db";

export default {
  name: "App",
  data() {
    return {
      books: []
    };
  },
  firestore: {
    books: db.collection("books")
  }
};
</script>

to get the id from books entries in our template.

Geopoints

Geopoints is something we can store with the Cloud Firestore.

For example, we can write:

<template>
  <div id="app">
    <div v-for="b of books" :key="b.id">{{b}}</div>
  </div>
</template>

<script>
import { db, GeoPoint } from "./db";

export default {
  name: "App",
  data() {
    return {
      books: []
    };
  },
  firestore: {
    books: db.collection("cities")
  },
  async mounted() {
    await db.collection("cities").add({
      name: "London",
      location: new GeoPoint(51.3, 0)
    });
  }
};
</script>

to add a GeoPoint instance with the latitude and longitude as its arguments.

Then the object created in the cities collection should have something like:

{ "name": "London", "location": { "latitude": 51.3, "longitude": 0 } }

We have the latitude and longitude properties in the entry.

Timestamps

We can also save timestamps with the Timestamp.fromDate method that comes with Vuefire.

It’s also available with Firestore only.

To use it, we can write:

<template>
  <div id="app">
    <div v-for="b of books" :key="b.id">{{b}}</div>
  </div>
</template>

<script>
import { db, Timestamp } from "./db";

export default {
  name: "App",
  data() {
    return {
      books: []
    };
  },
  firestore: {
    books: db.collection("events")
  },
  async mounted() {
    await db.collection("events").add({
      name: "parade",
      date: Timestamp.fromDate(new Date("2029-07-14"))
    });
  }
};
</script>

We pass in a Date instance into the fromDate method.

Then we get something like:

{ "name": "parade", "date": { "seconds": 1878681600, "nanoseconds": 0 } }

added to the events collection.

seconds is the UNIX timestamp in seconds.

Conclusion

We can save various items to Firebases’ Cloud Firestore in our Vue app with Vuefire.