vue-fiery

0.0.2 • Public • Published

vue-fiery

Vue.js binding for Google Firebase Cloud Firestore.

Features

  • Documents example
  • Collections (stored as array or map) example
  • Queries (stored as array or map) 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 to the document example
  • Callbacks (error, success, missing, remove) example
  • Custom binding / unbinding

Contents

Dependencies

  • Firebase ^5.0.0
  • Vue: ^1.0.28

Installation

npm

Installation via npm : npm install vue-fiery --save

Usage

import Vue from 'vue'
import VueFiery from 'vue-fiery'
import firebase from 'firebase'
 
require('firebase/firestore')
 
Vue.use(VueFiery)
 
const firebaseApp = firebase.initializeApp({ ... })
const db = firebaseApp.firestore();
 
var vm = new Vue({
  el: '#app',
  data() {
    return {
      todos: this.$fiery(db.collection('todos')) // live collection,
      ford: this.$fiery(db.collection('cars').doc('ford')), // live document
      role: 'admin'
    }
  },
  computed: {
    // Updated when role changes
    personsWithRole() {
      return this.$fiery(db.collection('persons'), {
        query: (q) => q.where('role', '==', this.role),
        type: Person
      })
    }
  }
})

Each record of the array will contain a .uid property. This helps identify what firestore database the document is stored, in what collection, and with which options

[
    {
        ".uid": "1///1///todos/-Jtjl482BaXBCI7brMT8",
        "name": "Star vue-fiery",
        "done": true
    }
]

Documents

const db = firebaseApp.firestore();
new Vue({
  inject: ['currentUserId'],
  data() {
    const $fiery = this.$fiery
    return {
      settings: $fiery(db.collection('settings').doc('system')),
      currentUser: $fiery(db.collection('users').doc(this.currentUserId)) // not reactive, but is updated real-time
    }
  }
})

Collections

const db = firebaseApp.firestore();
new Vue({
  data() {
    const $fiery = this.$fiery
    return {
      cars: $fiery(db.collection('cars')) // real-time array
      carMap: $fiery(db.collection('cars'), {map: true}) // real-time map: carMap[id] = car
    }
  }
})

Queries

const db = firebaseApp.firestore();
new Vue({
  inject: ['currentUserId'],
  data() {
    const $fiery = this.$fiery
    return {
      currentCars: $fiery(db.collection('cars'), { // real-time array
        query: (cars) => cars.where('created_by', '==', this.currentUserId)
      })
      currentCarMap: $fiery(db.collection('cars'), { // real-time map: currentCarMap[id] = car
        query: (cars) => cars.where('created_by', '==', this.currentUserId),
        map: true
      })
    }
  }
})

Real-time or once

const db = firebaseApp.firestore();
new Vue({
  inject: ['currentUserId'],
  data() {
    const $fiery = this.$fiery
    return {
      // real-time is default, all you need to do is specify once: true to disable it
      cars: $fiery(db.collection('cars'), {once: true}), // array populated once
      currentUser: $fiery(db.collection('users').doc(this.currentUserId), {once: true}), // current user populated once
    }
  }
})

Data or computed

const db = firebaseApp.firestore();
new Vue({
  inject: ['currentUserId'],
  data() {
    // data examples above
    return {
      limit: 25,
      status: 'unfinished'
    }
  },
  computed: {
    currentUser() {
      return this.$fiery(db.collection('users').doc(this.currentUserId)) // reactive and real-time
    },
    todos() {
      return this.$fiery(db.collection('todos'), { // reactive and real-time
        query: (todos) => todos
          .where('created_by', '==', this.currentUserId)
          .where('status', '==', this.status)
          .limit(this.limit),
 
      })
    }
  }
})

Adding, updating, overwriting, removing

const db = firebaseApp.firestore();
new Vue({
  inject: ['currentUserId'],
  data() {
    return {
      todos: this.$fiery(db.collection('todos'))
    }
  },
  computed: {
    currentUser() {
      return this.$fiery(db.collection('users').doc(this.currentUserId))
    }
  },
  methods: {
    addTodo() { // COLLECTIONS STORED IN $fires
      // once successful, this.todos will be updated
      this.$fires.todos.add({
        name: 'Like vue-fiery',
        done: true
      })
    },
    updateUser() {
      this.$fiery.update(this.currentUser)
    },
    updateUserEmailOnly() {
      this.$fiery.update(this.currentUser, ['email'])
    },
    updateAny(data) { // any document can be passed, ex: this.todos[1], this.currentUser
      this.$fiery.update(data)
    },
    overwrite(data) { // only fields present on data will exist on sync
      this.$fiery.sync(data)
    },
    remove(data) {
      this.$fiery.remove(data) // removes sub collections as well
      this.$fiery.remove(data, true) // preserves sub collections
    },
    removeName(todo) {
      this.$fiery.clear(data, '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!

const db = firebaseApp.firestore();
new Vue({
  data() {
    return {
      // this.todos[todoIndex].children[childIndex]
      todos: this.$fiery(db.collection('todos'), {
        sub: {
          children: { // creates an array or map on each todo object: todo.children[]
            // once, map, etc
            query: (children) => children.orderBy('updated_at')
          }
        }
      })
    }
  },
  methods: {
    addChild(parent) {
      // or this.$fiery.ref(parent, 'children') for short
      this.$fiery.ref(parent).collection('children').add({
        name: 'Fork vue-fiery',
        done: false
      })
    },
    clearChildren(parent) {
      this.$fiery.clear(parent, 'children') // clear the sub collection
    }
  }
})

Return instances of a class

function Todo() {
 
}
Todo.prototype = {
  markDone (byUser) {
    this.done = true
    this.updated_at = Date.now()
    this.updated_by = byUser.id
  }
}
 
const db = firebaseApp.firestore();
new Vue({
  data() {
    return {
      // this.todos[todoIndex] instanceof Todo
      todos: this.$fiery(db.collection('todos'), {
        type: Todo,
        // OR you can specify newDocument and do custom loading (good for polymorphic data)
        newDocument: function(initialData) {
          var instance = new Todo()
          instance.callSomeMethod()
          return instance
        }
      })
    }
  }
})

Active Record

// can be used with type, doesn't have to be
function Todo() {
 
}
Todo.prototype = {
  markDone (byUser) {
    this.done = true
    this.updated_at = Date.now()
    this.updated_by = byUser.id
    this.$update()
  }
}
 
const db = firebaseApp.firestore();
new Vue({
  data() {
    return {
      todos: this.$fiery(db.collection('todos'), {
        type: Todo,
        record: true
        // $sync, $update, $remove, $ref, $clear, $getChanges are functions added to every Todo instance
      }),
      todosCustom: this.$fiery(db.collection('todos'), {
        record: true,
        recordOptions: { // which methods do you want added to every object, and with what method names?
          sync: 'sync',
          update: 'save',
          remove: 'destroy'
          // we don't want $ref, $clear, or $getChanges
        }
      })
    }
  },
  methods: {
    updateTodoAt(index) {
      // instead of this.$fiery.update(this.todos[index])
      this.todos[index].$update()
    },
    saveTodoCustomAt(index) {
      // instead of this.$fiery.update(this.todosCustom[index])
      this.todosCustom[index].save()
    },
    done(todo) {
      todo.markDone(this.currentUser) // assuming currentUser exists
    },
    getChanges(todo) {
      todo.$getChanges(['name', 'done'], function(changes, saved, current) {
        // are there unsaved changes in name or done? (exclude array to check entire document)
      })
    }
  }
})

Save fields

const db = firebaseApp.firestore();
new Vue({
  data() {
    return {
      todos: this.$fiery(db.collection('todos'), {
        include: ['name', 'done'], // if specified, we ONLY send these fields on sync/update
        exclude: ['hidden'] // if specified here, will not be sent on sync/update
      }),
    }
  },
  methods: {
    save(todo) {
      this.$fiery.update(todo)
    },
    saveDone(todo) {
      this.$fiery.update(todo, ['done']) // only send this value if it exists
    },
    saveOverride(todo) {
      this.$fiery.update(todo, ['hidden']) // ignores exclude and include when specified
    }
  }
})

Encode & decode properties

const db = firebaseApp.firestore();
new Vue({
  data() {
    return {
      todos: this.$fiery(db.collection('todos'), {
        // convert server values to local values
        decoders: {
          status(remoteValue, remoteData) {
            return remoteValue === 1 ? 'done' : (remoteValue === 2 ? 'started' : 'not started')
          }
        },
        // convert local values to server values
        encoders: {
          status(localValue, localData) {
            return localValue === 'done' ? 1 : (localeValue === 'started' ? 2 : 0)
          }
        },
        // optionally instead of individual decoders you can specify a function
        decode(remoteData) {
          // do some decoding, maybe do something special
          return remoteData
        }
      })
    }
  }
})

Adding key to object

const db = firebaseApp.firestore();
new Vue({
  data() {
    return {
      todos: this.$fiery(db.collection('todos'), {key: 'id', exclude: ['id']}) // must be excluded manually
    }
  },
  methods: {
    log(todo) {
      // todo.id exists now
      console.log(todo)
    }
  }
})

Callbacks

const db = firebaseApp.firestore();
new Vue({
  data() {
    return {
      todos: this.$fiery(db.collection('todos'), {
        onSuccess: (todos) => {},
        onError: (message) => {},
        onRemove: () => {},
        onMissing: () => {} // occurs for documents
      })
    }
  }
})

LICENSE

MIT

Package Sidebar

Install

npm i vue-fiery

Weekly Downloads

2

Version

0.0.2

License

MIT

Unpacked Size

167 kB

Total Files

25

Last publish

Collaborators

  • philip.diffenderfer