fiery-vue
Vue.js binding for Google Firebase Cloud Firestore.
Relies on fiery-data - you can go there to see more advanced examples
Features
- Documents example
- Collections (stored as array or map) example
- Queries (stored as array or map) example
- Streams (stored as array or map) example
- Pagination example
- Real-time or once example
- Data or computed properties example
- Adding, updating, sync, removing, remove field example
- Sub-collections (with cascading deletions!) example
- Return instances of a class example
- Add active record methods (sync, update, remove, clear, getChanges) example
- Control over what properties are sent on save example
- Encode & decode properties example
- Adding the key and exists to the document example
- Sharing, extending, defining, and global options example
- Callbacks (error, success, missing, remove) example
- Custom binding / unbinding example
Contents
Dependencies
- fiery-data: ^0.0.7
- Firebase ^5.0.0 (a runtime dependency only, since you are passing the references)
- Vue: ^1.0.28 (not an actual dependency, since you are calling
Vue.use
yourself)
Installation
npm
Installation via npm : npm install --save fiery-vue
Usage
Vue const app = firebaseconst fs = firebase; el: '#app' fiery: true // required to add this.$fiery to this component { return todos: this // live collection, ford: this // live document role: 'admin' } computed: // Updated when role changes { const role = this const options = q type: Person return this }
Each object will contain a .uid
property. This helps identify what firestore
database the document is stored in, the collection, and with which options.
Documents
inject: 'currentUserId' fiery: true // required to add this.$fiery to this component { const $fiery = this$fiery return settings: currentUser: // not reactive, but is updated real-time }
Collections
fiery: true // required to add this.$fiery to this component { const $fiery = this$fiery return cars: // real-time array carMap: // real-time map: carMap[id] = car }
Queries
inject: 'currentUserId' fiery: true // required to add this.$fiery to this component { const $fiery = this$fiery return currentCars: currentCarMap: }
Streams
A stream is an ordered collection of documents where the first N are fetched, and any newly created/updated documents that should be placed in the collection
are added. You can look back further in the stream using more
. A use case for
streams are a message channel. When the stream is first loaded N documents are
read. As new messages are created they are added to the beginning of the collection. If the user wishes to see older messages they simply have to call
more
on the stream to load M more. The once
property does not work on streams, they are real-time only.
You MUST have an orderBy clause on the query option and stream
must be true
.
fiery: true // required to add this.$fiery to this component { const $fiery = this$fiery return // streams are always real-time, but can be an array or map messages: } methods: { // load 10 more this$fiery } { // load count more $fiery }
Pagination
{ return make: 'Honda' limit: 10 } computed: { const make limit = this // we have to reference these here for this to work return cars // required for prev() - orderBy's must be in reverse cars } { return this } { return this$fiery } methods: { thiscarsPagernext // next 10 please, returns a promise which resolves when they're fetched // this.carsPager.index // which page we're on // this.carsPager.hasNext() // typically returns true since we don't really know - unless cars is empty // this.carsPager.next() // executes the query again but on the next 10 results. index++ // this.carsPager.hasPrev() // looks at pager.index to determines if there's a previous page // this.carsPager.prev() // executes the query again but on the previous 10 results. index-- }
Real-time or once
inject: 'currentUserId' fiery: true // required to add this.$fiery to this component { const $fiery = this$fiery return // real-time is default, all you need to do is specify once: true to disable it cars: // array populated once currentUser: // current user populated once }
Data or computed
For computed properties the third parameter to $fiery
is required (it's best to just use the name of the property)
inject: 'currentUserId' fiery: true // required to add this.$fiery to this component { // data examples above return limit: 25 status: 'unfinished' } computed: { const currentUserId = this; const options = {} return this // reactive and real-time } { // For computed results you need to get the dependent variables early so they are properly tracked. // The query/queryReversed callback may not be called immediately, so they must be pulled out. const currentUserId status limit = this; const options = todos return this // reactive and real-time }
Adding, updating, overwriting, removing
inject: 'currentUserId' fiery: true // required to add this.$fiery to this component { return todos: this } computed: { const currentUserId = this; return this } methods: { // COLLECTIONS STORED IN $fires this$firestodos // OR const savedTodo = this$fiery } { this$fiery } { this$fiery } { // any document can be passed, ex: this.todos[1], this.currentUser this$fiery } { // only fields present on data will exist on sync this$fiery } { this$fiery // removes sub collections as well this$fiery // preserves sub collections } { this$fierycleardata 'name' // can also specify an array of props or sub collections }
Sub-collections
You can pass the same options to sub, nesting as deep as you want!
fiery: true // required to add this.$fiery to this component { return // this.todos[todoIndex].children[childIndex] todos: this } methods: { this$fiery // OR this$fiery // OR const savedChild = this$fiery // OR const unsavedChild = this$fiery } { this$fieryclearparent 'children' // clear the sub collection }
Return instances of a class
{ }Todoprototype = { thisdone = true thisupdated_at = Date thisupdated_by = byUserid } fiery: true // required to add this.$fiery to this component { return // this.todos[todoIndex] instanceof Todo todos: this }
Active Record
// can be used with type, doesn't have to be { }Todoprototype = { thisdone = true thisupdated_at = Date thisupdated_by = byUserid this // injected } fiery: true // required to add this.$fiery to this component { return todos: this todosCustom: this } methods: { // same as this.$fiery.update(this.todos[index]) thistodosindex } { // same as this.$fiery.update(this.todosCustom[index]) thistodosCustomindex } { todo // assuming currentUser exists } { // exclude array to compare entire document todo }
Save fields
fiery: true // required to add this.$fiery to this component { return todos: this } methods: { this$fiery // sends name and done as configured above } { this$fiery // only send this value if it exists } { this$fiery // ignores exclude and include when specified }
Encode & decode properties
fiery: true // required to add this.$fiery to this component { return todos: this }
Adding key and exists to object
fiery: true // required to add this.$fiery to this component { return todos: this // must be excluded manually from saving if include is not specified } methods: { // todo.id exists now console }
Sharing, extending, defining, and global options
// ==== Sharing ====let Todo = shared: true // necessary for non-global or defined options that are used multiple times include: 'name' 'done' 'done_at' // ==== Extending ====let TodoWithChildren = shared: true extends: Todo sub: children: Todo // ==== Defining ====FieryVue // or multipleFieryVue // ==== Global ====FieryVue fiery: true // required to add this.$fiery to this component { return comments: this // you can pass a named or Shared }
Callbacks
fiery: true // required to add this.$fiery to this component { return todos: this }
Binding and Unbinding
fiery: true // required to add this.$fiery to this component methods: { thistodos = this } { this$fiery }